一个servlet处理多个请求方法

实现思路    1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个    非常消耗性能的操作,这种操作应该只需要进行一次    2.进行类的解析        目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法,    解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作

3.将解析的结果进行缓存        这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的,    所以我们需要将这些信息缓存再存入到服务器中

一、自定义注解类
package org.nf.framework.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 描述:
 *
 * @author lance
 * 自定义注解
 * @Retention –什么时候使用该注解
 * @Target –注解用于什么地方
 *  RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,
 *  因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
 *  ElementType.METHOD:用于描述方法
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UrlMapping {
    String value();
}

二、扫描工具类,得到项目中所有的包名和类名

package org.nf.framework.utils;

import java.io.File;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
/**
 * 扫描工具类,用于扫描指定包下面的所有类,包括子包
 * @author lance
 *
 */
public class ScanUtil {
    /**
     * 存放所有类的类名
     */
    private static List<String> list = new ArrayList<String>();

    /**
     * 扫描
     * @param packagePath
     * @return
     */
    public static List<String> scanPackage(String packages) {
        String[] packs = packages.split(",");
        for (String pack : packs) {
            String path = toPackagePath(pack);
            try {
                toClassPath(path);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return list;
    }

    /**
     * 将路径转换成包名
     * @param packagePath
     * @return
     */
    private static String toPackagePath(String packagePath) {
        packagePath = packagePath.replace(".", File.separator);
        return getRealPath()+packagePath;
    }
    /**
     * 遍历目录将类名存入List中
     * @param classPath
     * @throws Exception
     */
    private static void toClassPath(String classPath) throws Exception {
        classPath = URLDecoder.decode(classPath, "utf-8");
        // listFiles()获取路径下的所有文件或文件夹,返回的是一个File[]数组
        File[] fs = new File(classPath).listFiles();
        if (fs != null) {
            for (File file : fs) {
                // file.isDirectory()方法判断当前额的file对象是否是一个文件夹
                if (file.isDirectory()) {
                    // 获取文件夹的绝度路径
                    // 递归调用
                    toClassPath(file.getAbsolutePath());
                } else {
                    // 将文件名转换成完整类名
                    String path = toClassName(file);
                    if (path != null)
                        list.add(path);
                }
            }
        }
    }

    /**
     *  将文件名转换成完整类名
     * @param file
     * @return
     * @throws Exception
     */
    private static String toClassName(File file) throws Exception {
        if (file.getName().endsWith(".class")) {
            String path = URLDecoder.decode(getRealPath(), "utf-8");
            path = new File(path).getAbsolutePath() + File.separator;
            path = file.getAbsolutePath().substring(path.length(),
                    file.getAbsolutePath().length());
            String className = path.replace(File.separator, ".");
            className = className.substring(0, className.length() - 6);
            return className;
        } else {
            return null;
        }
    }

    /**
     * 获取当前项目的classes目录
     * @return
     */
    private static String getRealPath(){
        return ScanUtil.class.getClassLoader().getResource("").getPath();
    }
}

三、servlet总控制器(相当于中央处理器,处理所有的servlet请求,核心)

package org.nf.framework.web;

import org.nf.framework.annotation.UrlMapping;
import org.nf.framework.utils.ScanUtil;

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.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 描述:
 * 总控制器
 *
 * @author lance
 * @create 2018-08-31 9:48
                实现思路
    1.进行全局扫描:将项目下所标识有注解的方法进行收集和解析(注意:扫描是一个
    非常消耗性能的操作,这种操作应该只需要进行一次
)
    2.进行类的解析
        目的:找到哪些类中有哪些方法是标识有注解的,那么这些方法就是用于请求处理的方法,
    解析的过程也是同样消耗性能的,思考一下,是否每次请求都要进行一次相同的解析操作

    3.将解析的结果进行缓存
        这一步非常重要,因为解析的结果将直接为后续的请求服务,在整个项目的运行同期是不能销毁的,
    所以我们需要将这些信息缓存再存入到服务器中
 */
public class DispatcherServlet extends HttpServlet {

    private static final Map<String, Method> mapper = new HashMap<>();
    @Override
    public void init(ServletConfig config) throws ServletException {
        //1.全局的扫描(空代表全局,也可以给某个包的值)
        List<String> className = scan("");
        //2.解析类中有注解的方法
        resolve(className);
        System.out.println("DispatcherServlet初始化完成。。。。");
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求的url,这个path其实就对应了mapper中的key
        String path = req.getServletPath();
        //根据key取出相应的method并调用处理请求
        //根据相应的key取出相应method,并调用方法
        invokeTargetMethod(req,resp,mapper.get(path));
    }

    /**
     * 进行类扫描
     * */
    private List<String> scan(String packageName){
        return  ScanUtil.scanPackage(packageName);
    }

    /**
     * 解析类中的注解方法
     * */
    private void resolve(List<String> className){
        for (String s : className) {
            try {
                //进行类加载
                Class<?> clazz= Class.forName(s);
                //获得类中的所有的方法
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if(method.isAnnotationPresent(UrlMapping.class)){
                        //获得所有注解方法的上value值,也就是请求url的值
                        String url = method.getAnnotation(UrlMapping.class).value();
                        //缓存到map集合中
                        mapper.put(url,method);
                    }
                }

            } catch (ClassNotFoundException e) {
               throw new RuntimeException(e.getMessage());
            }
        }
    }

    /**
     *调用具体某目标的方法
     * */
    private void invokeTargetMethod(HttpServletRequest request,HttpServletResponse response,Method method){

        try {
            //先获得该类中的实例
            Object instance = method.getDeclaringClass().newInstance();
            //回调方法
            method.invoke(instance,request,response);
        } catch (InstantiationException e) {
            throw new RuntimeException(e.getMessage());
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e.getMessage());
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e.getMessage());
        }

    }
}

四、具体servlet请求实现类

package org.nf.framework.Test;

import org.nf.framework.annotation.UrlMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 描述:
 * 具体处理请求
 *
 * @author lance
 * @create 2018-08-31 11:16
 */

public class Collectors {
    @UrlMapping("/login")
    public void Login(HttpServletRequest request, HttpServletResponse response){
        String name = request.getParameter("userName");
        String password = request.getParameter("password");
        System.out.println(name);
        System.out.println(password);
        System.out.println("login.....");
    }

    @UrlMapping("/regist")
    public void regist(HttpServletRequest request, HttpServletResponse response){
        System.out.println(".....");
    }

}
 

原文地址:https://www.cnblogs.com/gepuginy/p/9726557.html

时间: 2024-10-10 00:46:25

一个servlet处理多个请求方法的相关文章

Servlet(五):一个Servlet处理多个请求

一.为什么要使用一个Servlet来处理多个请求? 当浏览器发送了一次请求到服务器时,servlet容器会根据请求的url-pattern找到对应的Servlet类,执行对应的doPost或doGet方法,再将响应信息返回给浏览器,这种情况下,一个具体的Servlet类只能处理对应的web.xml中配置的url-pattern请求,一个Servlet类,一对配置信息.如果业务扩展,需要三个Servlet来处理请求,就需要再加上两个具体的Servlet类,两对配置信息,如果继续向上扩展,是不是会认

【WEB小工具】BaseServlet—一个Servlet处理多个请求

1 package cn.itcast.test.web.servlet; 2 3 import java.io.IOException; 4 import java.io.PrintWriter; 5 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.ser

一个servlet处理多个请求,地址字符串怎么处理呢

package web; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import javax.servlet.ServletException; import javax.servlet.

jsp如何包含一个servlet?请举一个例子?

想要包含一个servlet得用下列的方法,it is alleged that include file="servlet1" can not work.(视频下载) (全部书籍) 例 4.4.2 <html><body>    <jsp:include page="/Cookie/DeleteCookie" flush="true" /></body></html> package c

一个Servlet中可以有多个处理请求的方法

BaseServlet 一个请求写一个Servlet太过复杂和麻烦,我们希望在一个Servlet中可以有多个处理请求的方法. 客户端发送请求时,必须给出一个参数,用来说明要调用的方法 方法的结构和service()方法的结构一样 初始版 当我们访问Servlet时,发生了那些操作? 首先是通过<url-pattern>找到<servlet-name>,通过<serlvet-name>最终找到<servlet-class>,也就是类名,在通过反射得到Serlv

利用java 反射机制来实现一个servlet处理多种请求

如果我们想在一个servlet中处理多种请求(比如新闻的添加.删除),简单的可以在jsp提交表单的action路径中添加一个键值对,然后再servlet中接收后根据不同的值来调用不同的方法. jsp端 1 <form action="newsServlet?method=add" method="post"> 2 <input type="text" ..> 3 <input type="submit&qu

接口测试基础知识详解http请求由三部分组成,分别是:请求行、消息报头、请求正文 1、请求行以一个方法符号开头,以空格分开,后面跟着请求的URI和协议的版本,格式如下:Method Request-URI HTTP-Version CRLF 其中 Method表示请求方法;Request-URI是一个统一资源标识符;HTTP-Version表示请求的HTTP协议版本;CRLF表示回车和换行(除了

HTTP URL (URL是一种特殊类型的URI,包含了用于查找某个资源的足够的信息)的格式如下:http://host[":"port][abs_path]http表示要通过HTTP协议来定位网络资源:host表示合法的Internet主机域名或者IP地址:port指定一个端口号,为空则使用缺省端口80:abs_path指定请求资源的URI:如果URL中没有给出abs_path,那么当它作为请求URI时,必须以"/"的形式给出,通常这个工作浏览器自动帮我们完成.e

servlet请求转发到另一个servlet

servlet请求转发到另一个servlet,并传递数据 . 1.通过request.setAttribute("key",value)给request加信息. 2.通过request.getRequestDispather(目标servlet).forward(request,response) 传递制定servlet. 3.在另一个servlet中通过request.getAttribute("key")来获取附加信息的值.

当多个客户请求一个servlet时,引擎为每个客户启动一个线程,那么servlet类的成员变量被所有的线程共享?

因为servlet的实现是单例,多线程也就是说,N个客户端请求同一个servlet,他们所请求的是同一个对象,成员变量是属于这个对象的,因此成员变量也被共享了因此在servlet编程中,无状态的servlet(就是不写属性,所以变量都在dopost或者doget里面)是线程安全的,否则,由于会共享到成员变量,因此就有可能不是线程安全的.