关于java:简单实现springmvc中的请求处理

33次阅读

共计 9995 个字符,预计需要花费 25 分钟才能阅读完成。

自定义 MVC 框架中的一些元素

一些注解

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {String value () default "";
}

@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {String value () default "";
}

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {String value () default "";
}

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {String value () default "";
}

解决对象封装

public class Handler {

    private Object controller;//Controller 对应的类
    private Method method;// 执行业务的办法
    private Pattern pattern;//uri
    private Map<String,Integer> paramIndexMapping;// 参数和地位的映射

    public Handler(Object controller, Method method, Pattern pattern) {
        this.controller = controller;
        this.method = method;
        this.pattern = pattern;
        this.paramIndexMapping = new HashMap<>();}

    public Object getController() {return controller;}

    public void setController(Object controller) {this.controller = controller;}

    public Method getMethod() {return method;}

    public void setMethod(Method method) {this.method = method;}

    public Pattern getPattern() {return pattern;}

    public void setPattern(Pattern pattern) {this.pattern = pattern;}

    public Map<String, Integer> getParamIndexMapping() {return paramIndexMapping;}

    public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {this.paramIndexMapping = paramIndexMapping;}
}

自定义 DisptchServelet 解决代码

public class DispatchServelet extends HttpServlet {private Properties properties = new Properties();
    private List<String> classNames = new ArrayList<>();
    private Map<String,Object> ioc =new HashMap<>();
    private List<Handler> handlerMapping = new ArrayList<>();
    @Override
    public void init(ServletConfig config) throws ServletException {
        // 加载配置文件
        String contextConfigLocation = config.getInitParameter("contextConfigLocation");
        doLoadConfig(contextConfigLocation);
        // 扫描相干的类,扫描注解
        doScan(properties.getProperty("scanPackage"));
        // 初始化 bean, 基于注解
        doInstance();
        // 实现依赖注入
        doAutoWired();
        // 实现处理器映射器,将 url 和 method 进行关联
        initHandlerMapping();
        System.out.println("mvc 初始化实现");
        
    }
    // 执行的是办法和 url 办法映射
    private void initHandlerMapping() {if (ioc.isEmpty()){return;}
        for (Map.Entry<String,Object> entry :ioc.entrySet()){Class<?> aClass = entry.getValue().getClass();
            if (!aClass.isAnnotationPresent(Controller.class)){continue;}
            String baseUrl = "";
            if (aClass.isAnnotationPresent(RequestMapping.class)){RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
                baseUrl=requestMapping.value();}
            Method[] methods= aClass.getMethods();
            for (int i=0;i<methods.length;i++){Method method = methods[i];
                if (!method.isAnnotationPresent(RequestMapping.class)){continue;}
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                String methodUrl = requestMapping.value();
                String url = baseUrl+methodUrl;
                Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url));
                Parameter[] parameters = method.getParameters();
                for (int j=0;j<parameters.length;j++){Parameter parameter = parameters[j];
                    if (parameter.getType().equals(HttpServletRequest.class)||parameter.getType().equals(HttpServletResponse.class)){handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j);
                    }else {handler.getParamIndexMapping().put(parameter.getName(),j);
                    }
                }
                // 实现办法和 url 的映射关系
                handlerMapping.add(handler);
            }
        }
    }
    // 执行注入局部,同样是做的 ioc 的局部性能
    private void doAutoWired() {if (ioc.isEmpty()){return;}
        for (Map.Entry<String,Object> entry :ioc.entrySet()){Field[] declareFields = entry.getValue().getClass().getDeclaredFields();
            for (int i=0;i<declareFields.length;i++){Field declareField = declareFields[i];
                if (!declareField.isAnnotationPresent(Autowired.class)){continue;}
                Autowired autowired = declareField.getAnnotation(Autowired.class);
                String beanName = autowired.value();
                if ("".equals(beanName.trim())){beanName=declareField.getType().getName();}
                declareField.setAccessible(true);
                try {
                    // 间接将这个字段的值设置为 ioc 中曾经示例化的类,// 即是实现了 ioc 中的实例化交给容器来治理的状况
                    declareField.set(entry.getValue(),ioc.get(beanName));
                } catch (IllegalAccessException e) {e.printStackTrace();
                }
            }

        }
    }

    // 执行的是符合要求的类的初始化,实际上是实现的一部分 ioc 的性能
    private void doInstance()  {if (classNames.size()==0){return;}
        try {for (int i=0;i<classNames.size();i++){String className = classNames.get(i);
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)){String simpleName = clazz.getSimpleName();
                    String lowerFirst = lowerFirst(simpleName);
                    Object o = clazz.newInstance();
                    // 因为 controller 无别名,所以简略设置成首字母小写就行
                    ioc.put(lowerFirst,o);
                }else if (clazz.isAnnotationPresent(Service.class)){Service service = clazz.getAnnotation(Service.class);
                    String beanName =service.value();
                    if (!"".equals(beanName.trim())){ioc.put(beanName,clazz.newInstance());
                    }else {beanName = lowerFirst(clazz.getSimpleName());
                        ioc.put(beanName,clazz.newInstance());
                    }

                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (int j=0;j<interfaces.length;j++){Class<?> ainterface = interfaces[j];
                        System.out.println(ainterface.getName());
                        // 将实现类和接口进行绑定
                        ioc.put(ainterface.getName(),clazz.newInstance());
                    }
                }else {continue;}
            }
        }catch (Exception e){e.printStackTrace();
        }

    }


    private  String lowerFirst(String className){char[] chars = className.toCharArray();
       if ('A'<chars[0]&&chars[0]<'Z'){chars[0]+=32;
       }
       return new String(chars);
    }
    private void doScan(String basePackage) {
        // 获取到指定包下的所有类的类名
        String scanPackagePath= Thread.currentThread().getContextClassLoader().getResource("").getPath()+basePackage.replaceAll("\\.","/");
        File pack = new File(scanPackagePath);
        File [] files = pack.listFiles();
        for (File file:files){if (file.isDirectory()){doScan(basePackage+"."+file.getName());
            }else if (file.getName().endsWith(".class")){String className = basePackage+"."+file.getName().replaceAll(".class","");
                classNames.add(className);
            }
        }
    }
    // 实现加载 web.xml 中配置的文件的门路
    private void doLoadConfig(String contextConfigLocation) {InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {properties.load(inputStream);
        } catch (IOException e) {e.printStackTrace();
        }
    }


    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Handler handler = getHander(req);
        if (handler==null){resp.getWriter().write("404 not found");
            return;
        }
        Class<?> [] parameterTypes = handler.getMethod().getParameterTypes();
        Object[] paraValues = new Object[parameterTypes.length];

        Map<String,String[]> parameterMap = req.getParameterMap();
        for (Map.Entry<String,String[]> param:parameterMap.entrySet()){String value = StringUtils.join(param.getValue(),",");
            if (!handler.getParamIndexMapping().containsKey(param.getKey())){continue;}
            // 对应理论参数的地位
            Integer index = handler.getParamIndexMapping().get(param.getKey());
            paraValues[index]=value;

        }
        // 对应上 req, 和 resp 参数的地位
        int reqIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName());
        paraValues[reqIndex]=req;
        int respIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName());
        paraValues[respIndex]=resp;

        try {
            // 理论执行的是 controller 中的办法
            handler.getMethod().invoke(handler.getController(),paraValues);
            System.out.println("执行 controller 办法胜利");
        } catch (IllegalAccessException e) {e.printStackTrace();
        } catch (InvocationTargetException e) {e.printStackTrace();
        }

    }

    private Handler getHander(HttpServletRequest req) {if (handlerMapping.isEmpty()){return null;}
        String url =req.getRequestURI();
        for (Handler handler:handlerMapping){Matcher matcher = handler.getPattern().matcher(url);
            if (!matcher.matches()){continue;}
            return handler;
        }
        return null;
    }

}

测试代码

public interface DemoService {String getName(String name);
}



@Service("demoService")
public class DemoServiceImpl implements DemoService {
    @Override
    public String getName(String name) {return name;}
}

@Controller
@RequestMapping("/demo")
public class DemoController {
    @Autowired
    private DemoService demoService;
    @RequestMapping("/query")
    public String query(HttpServletRequest req, HttpServletResponse resp,String name){return demoService.getName(name);
    }
}

web.xml 配置

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>com.zhao.mvcframework.servelet.DispatchServelet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>mvc.properties</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

mvc.properties 的配置

scanPackage=com.zhao.mvcdemo

pom 文件的配置

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.zhao</groupId>
  <artifactId>mvc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>mvc Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.10</version>
    </dependency>
  </dependencies>

  <build>
      <plugins>
        <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.2</version>
          <configuration>
            <port>8080</port>
            <path>/</path>
          </configuration>

        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>utf-8</encoding>
              <compilerArgs>-parameters</compilerArgs>
            </configuration>
        </plugin>
      </plugins>
  </build>
</project>

测试时拜访具体的 http://localhost:8080/demo/query?name=zhaozhen 无问题

代码地址为 https://github.com/zhendiao/d…

欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】

正文完
 0