前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单实现springmvc中的请求处理

简单实现springmvc中的请求处理

作者头像
zhaozhen
发布2021-07-15 10:48:56
5960
发布2021-07-15 10:48:56
举报
文章被收录于专栏:微瞰Java后端开发

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

一些注解

代码语言:javascript
复制
@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 "";
}

处理对象封装

代码语言:javascript
复制
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处理代码

代码语言:javascript
复制
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;
    }

}

测试代码

代码语言:javascript
复制
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配置

代码语言:javascript
复制
<!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的配置

代码语言:javascript
复制
scanPackage=com.zhao.mvcdemo

pom文件的配置

代码语言:javascript
复制
<?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/deme-code/tree/main/mvc

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微瞰技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自定义MVC框架中的一些元素
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档