文章来自:https://www.jianshu.com/p/2bbb693a833a
收到请求并且鉴权后会自动映射请求到方法上来
1、定义@Controller 注解,标识类需要被扫描
/** * 标识类需要被扫描 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Controller { }
2、定义@RequestMapping 注解,标识类需要被扫描
/** * 映射url到类和方法上 */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface RequestMapping { //url String value(); //默认为GET RequestMethod method() default RequestMethod.DEFAULT; //是否需要身份验证 boolean auth() default true; }
3、RequestMethod 用于枚举请求的方法
/** * 请求方法枚举,只枚举了我们需要的方法 */ public enum RequestMethod { GET, POST, DELETE, DEFAULT }
4、RequestHandler 用于存放url映射到方法的相关信息
/** * 请求处理者类 * * @author Jerry * @date 2019/7/22 11:01 */ public class RequestHandler { //映射的路径 public String path; //方法GET、POST等 public RequestMethod requestMethod; //类对象 public Class clazz; //方法对象 public Method method; //类的实例对象 public Object instance; //是否需要身份验证 public boolean isAuth; }
5、RequestMappingProcessor 用于扫描注解
/** * 注解扫描器 * * @author Jerry * @date 2019/7/22 10:51 */ public class RequestMappingProcessor { //存放url到RequestHandler的映射 public static HashMap<String, RequestHandler> requestMappingMap = new HashMap<>(); /** * 扫描解析指定包下的@Controller和@RequestMapping注解 * <p> * 只能扫描class文件,暂未实现扫描jar包 * * @return 生成的映射表 */ public static HashMap<String, RequestHandler> scanRequestMapping() { //扫描的包路径 final String pkgPath = "com/zlt/controller"; //用于字符拼接 final String pkgClassPath = pkgPath.replace("/", ".") + "."; requestMappingMap.clear(); Enumeration<URL> enumeration = null; try { //获取该包下的class文件 enumeration = Thread.currentThread().getContextClassLoader().getResources(pkgPath); } catch (IOException e) { e.printStackTrace(); } if (enumeration == null) { System.out.println("扫描失败"); return null; } try { while (enumeration.hasMoreElements()) { URL url = enumeration.nextElement(); File file = new File(url.getFile()); String[] fileList = file.list(); if (fileList == null) { System.err.println(file.getAbsolutePath() + "包没有类"); return null; } for (String path : fileList) { Class clazz = Thread.currentThread().getContextClassLoader().loadClass(pkgClassPath + path.substring(0, path.length() - 6)); Controller controller = (Controller) clazz.getAnnotation(Controller.class); if (controller != null) { System.out.println(clazz.getName()); RequestMapping parentRequestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class); //类注解上的一级路径 String basePath = null; RequestMethod baseMethod = null; if (parentRequestMapping != null) { //获取类注解上的一级路径 basePath = ensurePath(parentRequestMapping.value()); baseMethod = parentRequestMapping.method(); //忽略类注解上的auth //baseAuth = parentRequestMapping.auth(); //默认为RequestMethod.GET if (baseMethod == RequestMethod.DEFAULT) baseMethod = RequestMethod.GET; } //生成类的实例对象 Object instance = clazz.newInstance(); System.out.println("扫描到类 " + instance.getClass().getCanonicalName()); for (Method method : clazz.getDeclaredMethods()) { System.out.println(" " + method.getName() + "()"); RequestMapping requestMapping = method.getAnnotation(RequestMapping.class); if (requestMapping != null) {//获取到方法上的注解 method.setAccessible(true); //生成RequestHandler实例 RequestHandler warp = new RequestHandler(); //拼接生成最终的url warp.path = basePath + ensurePath(requestMapping.value()); //获取方法注解上的RequestMethod RequestMethod requestMethod = requestMapping.method(); if (requestMethod == RequestMethod.DEFAULT) { //如果类注解设置了RequestMethod,而方法注解没有设置RequestMethod,则类注解会覆盖方法注解的请求方法 warp.requestMethod = baseMethod != null ? baseMethod : RequestMethod.GET;//默认为GET } else {//否则使用方法注解上的RequestMethod warp.requestMethod = requestMethod; } warp.method = method; //默认为true warp.isAuth = requestMapping.auth(); warp.clazz = clazz; warp.instance = instance; //检查参数,这里还可以再检查一下返回值类型什么的 //这里的方法参数类型和个数都是定死了,可以拓展支持不同参数类型和返回类型 if (method.getParameterCount() == 2) { Class<?>[] classes = method.getParameterTypes(); if (HttpServletRequest.class == classes[0] && HttpServletResponse.class == classes[1]) { requestMappingMap.put(warp.path, warp); continue; } } System.err.println(method.getName() + " 参数错误"); } } } } } } catch (Exception e) { e.printStackTrace(); } if (requestMappingMap != null) { System.out.println("url映射:"); for (Map.Entry<String, RequestHandler> entry : requestMappingMap.entrySet()) { RequestHandler warp = entry.getValue(); System.out.println(warp.path + " " + warp.requestMethod + " " + warp.clazz.getCanonicalName() + "." + warp.method.getName() + "()"); } } return requestMappingMap; } /** * 规范url格式 * <p> * 标准格式为前有ur开头l“/”而后面没有 如 /user、/user/login等 */ private static String ensurePath(String path) { if (!path.startsWith("/")) { path = "/" + path; } if (path.endsWith("/")) { path = path.substring(0, path.length() - 1); } return path; } public static HashMap<String, RequestHandler> getRequestMappingMap() { return requestMappingMap; } }
6、定义过滤器 RequestFilter ,过滤没有映射的url
/** * Request过滤类 * <p> * 通过url、method等过滤未映射的Request * * @author Jerry * @date 2019/7/23 15:57 */ public class RequestFilter implements Filter { private HashMap<String, RequestHandler> handlerMap = RequestMappingProcessor.getRequestMappingMap(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = ((HttpServletRequest) servletRequest); String fullPath = request.getPathInfo(); RequestHandler handler = handlerMap.get(fullPath); if (handler != null) { //把处理者添加到request的attribute中 request.setAttribute(Config.KEY_REQUEST_HANDLER, handler); filterChain.doFilter(servletRequest, servletResponse); } else { //直接就不往下传递请求了,这里可以处理一下,排除一下页面 如druid System.out.println(request.getRequestURI() + ":没有映射"); } } }
7、定义过滤器 AuthenticationFilter ,用于请求鉴权
/** * 用来过滤未登录的请求 * * @author Jerry * @date 2019/7/22 14:16 */ public class AuthenticationFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { if (servletRequest.getAttribute(Config.KEY_REQUEST_DRUID) != null) { filterChain.doFilter(servletRequest, servletResponse); return; } RequestHandler handler = (RequestHandler) servletRequest.getAttribute(Config.KEY_REQUEST_HANDLER); if (handler != null) { if (handler.isAuth) {//如果需要验证身份 boolean isLogin = false; try { //这里始终为false,需要实现鉴权逻辑 isLogin = false; } catch (Exception e) { e.printStackTrace(); } if (isLogin) {//如果鉴权通过 filterChain.doFilter(servletRequest, servletResponse); } else { //如果鉴权没通过 } } else { filterChain.doFilter(servletRequest, servletResponse); } } else { //处理者为空情况 System.out.println("AuthenticationFilter:" + ((HttpServletRequest) servletRequest).getRequestURI()); } } }
8、DispatchServlet 用于执行分发请求到对应方法上
/** * 负责分发请求的Servlet * <p> * 根据配置,分发请求到不同的方法 * * @author Jerry * @date 2019/7/20 17:41 */ public class DispatchServlet extends HttpServlet { @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestHandler handler = (RequestHandler) request.getAttribute(Config.KEY_REQUEST_HANDLER); if (handler != null) { try { Object data = handler.method.invoke(handler.instance, request, response); //自己处理返回值 } catch (Exception e) { response.getWriter().write(ResponseBody.JSON_ERROR_SYSTEM); e.printStackTrace(); } } else { System.err.println(request.getRequestURI()); } } }
注解(@RequestMapping)实现url映射到方法(仿照Spring MVC实现)
原文:https://www.cnblogs.com/yanjiexiansheng/p/12209284.html