用idea手写spring

3 篇文章 0 订阅
0 篇文章 0 订阅

1、利用模板创建一个maven项目。

2、创建项目目录,架构设计如下

3、添加pom依赖,仅此一个,在<dependencies></dependencies>中 添加,其他为初始化默认数据。

 <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
      <scope>provided</scope>
 </dependency>

4、 在web.xml添加路径映射,application.properties会标红,这个数据正常不用管。

<!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>springmvc</servlet-name>
    <servlet-class>com.spring.mvcframework.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>application.properties</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

5、application.properties内容就一行。

scanPackage=com.spring.demo

6、各注解实现

package com.spring.mvcframework.annotation;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DwbAutowired {
    String value() default "";
}
package com.spring.mvcframework.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DwbController {
    String value() default "";
}
package com.spring.mvcframework.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DwbRequestMapping {
    String value() default "";
}
package com.spring.mvcframework.annotation;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DwbRequestParam {
    String value() default "";
}
package com.spring.mvcframework.annotation;

import java.lang.annotation.*;

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

7、DemoAction类。注意注入时要写接口,不能是实现类,不然访问会报空指针异常,即注入的service为null。

package com.spring.demo.action;

import com.spring.demo.service.DemoService;
import com.spring.mvcframework.annotation.DwbAutowired;
import com.spring.mvcframework.annotation.DwbController;
import com.spring.mvcframework.annotation.DwbRequestMapping;
import com.spring.mvcframework.annotation.DwbRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@DwbController
@DwbRequestMapping("/demo")
public class DemoAction {

    @DwbAutowired
    private DemoService demoService;


    @DwbRequestMapping("/get")
    public void get(HttpServletRequest req, HttpServletResponse res,
                    @DwbRequestParam("name") String name) {
        System.out.println(" 参数:====================" + name);
        String result = demoService.get(name);
        try {
            res.getWriter().write(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @DwbRequestMapping("/add")
    public void add(HttpServletRequest req, HttpServletResponse res,
                    @DwbRequestParam("number1") Integer number1, @DwbRequestParam("number2") Integer number2) {
        try {
            res.getWriter().write(number1 + "+" + number2 + "=" + (number1 + number2));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @DwbRequestMapping("delete")
    public void delete(HttpServletRequest req, HttpServletResponse res,
                       @DwbRequestParam("id") Integer id) {
        System.out.println(" 参数:====================" + id);
        String result = "id" + id + "已删除";
        try {
            res.getWriter().write(result);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

8、DemoService接口

package com.spring.demo.service;

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

9、DemoService接口实现DemoServiceImpl

package com.spring.demo.service;

import com.spring.mvcframework.annotation.DwbService;

@DwbService
public class DemoServiceImpl implements DemoService {

    public String get(String name) {
        return "hello" + name;
    }
    
}

10、DispatcherServlet类,doInstance方法中有newInstance要注意servlet-api的版本,详见方法上的注释。

package com.spring.mvcframework.servlet;

import com.spring.mvcframework.annotation.DwbAutowired;
import com.spring.mvcframework.annotation.DwbController;
import com.spring.mvcframework.annotation.DwbRequestMapping;
import com.spring.mvcframework.annotation.DwbService;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class DispatcherServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    //跟web.xml中param-name的值一致
    private static final String LOCATION = "contextConfigLocation";

    //保存所有配置信息
    private Properties p = new Properties();

    //保存所有被扫描到的相关的类名
    private List<String> classNames = new ArrayList<String>();

    //核心IOC容器, 保存所有初始化的Bean
    private Map<String, Object> ioc = new HashMap<String, Object>();

    private Map<String, Method> handlerMapping = new HashMap<String, Method>();

    public DispatcherServlet() {
        super();
    }

    /**
     *  初始化,加载配置文件
     *
     * @param config 配置
     */
    public void init(ServletConfig config) {
        //1、加载配置文件
        doLoadConfig(config.getInitParameter(LOCATION));

        //2、扫描所有相关的类
        doScanner(p.getProperty("scanPackage"));

        //3、初始化所有相关的实例,并保存到IOC容器中
        doInstance();

        //4、依赖注入
        doAutowired();

        //5、构造HandlerMapping
        initHandleMapping();

        //6、等待请求 匹配URL,定位方法,反射调用执行
        //调用doGet方法或doPost方法

        //提示信息
        System.out.println("spring mvc framework is init");

    }

    private void doLoadConfig(String location) {
        InputStream fis = null;
        try {
            fis = this.getClass().getClassLoader().getResourceAsStream(location);

            //读取配置文件
            if (null == fis){
                System.out.println("扫描文件不应该为空=============");
            }
            p.load(fis);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != fis) {
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void doScanner(String packageName) {
        //将所有的包路径替换为文件路径
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            //如果是文件夹,继续递归
            if (file.isDirectory()) {
                doScanner(packageName + "." + file.getName());
            } else {
                classNames.add(packageName + "." + file.getName().replaceAll(".class", "").trim());
            }
        }
    }

    /**
     * IOC容器的key默认是类名首字母小写,如果是自己自己设置类名,则优先使用自定义的。
     *
     * @param str 类名
     * @return 仅转换首字母的字符串
     */
    private String lowerFirstCase(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * 
     *  下面的clazz.getDeclaredConstructor().newInstance()
     *  在3.0.1之前使用 clazz.newInstance()
     *     
     */
    private void doInstance() {
        if (classNames.size() == 0) {
            return;
        }
        try {
            for (String classNameItem : classNames) {
                Class<?> clazz = Class.forName(classNameItem);
                if (clazz.isAnnotationPresent(DwbController.class)) {
                    //默认首字母小写作为beanName
                    String beanName = lowerFirstCase(clazz.getSimpleName());
                    ioc.put(beanName, clazz.getDeclaredConstructor().newInstance());
                } else if (clazz.isAnnotationPresent(DwbService.class)) {
                    DwbService service = clazz.getAnnotation(DwbService.class);
                    String beanName = service.value();

                    //如果用户设置了名字,就用用户自己的设置
                    if (!"".equals(beanName.trim())) {
                        ioc.put(beanName, clazz.getDeclaredConstructor().newInstance());
                        continue;
                    }

                    //如果用户没设,就按接口类型创建一个实例
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> i : interfaces) {
                        ioc.put(i.getName(), clazz.getDeclaredConstructor().newInstance());
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private void doAutowired() {
        if (ioc.isEmpty()) {
            return;
        }

        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            //拿到实例对象中的所有属性
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(DwbAutowired.class)) {
                    continue;
                }

                DwbAutowired autowired = field.getAnnotation(DwbAutowired.class);
                String beanName = autowired.value().trim();
                if ("".equals(beanName)) {
                    beanName = field.getType().getName();
                }
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(), ioc.get(beanName));
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    }


    private void initHandleMapping() {
        if (ioc.isEmpty()) {
            return;
        }

        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();
            if (!clazz.isAnnotationPresent(DwbController.class)) {
                continue;
            }

            String baseUrl = "";

            //获取Controller的url配置
            if (clazz.isAnnotationPresent(DwbRequestMapping.class)) {
                DwbRequestMapping requestMapping = clazz.getAnnotation(DwbRequestMapping.class);
                baseUrl = requestMapping.value();
            }

            //获取Method的url值
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                //没有加RequestMapping注解的直接忽略
                if (!method.isAnnotationPresent(DwbRequestMapping.class)) {
                    continue;
                }

                //映射URL
                DwbRequestMapping requestMapping = method.getAnnotation(DwbRequestMapping.class);
                String url = ("/" +baseUrl +"/" + requestMapping.value()).replaceAll("/+", "/");
                handlerMapping.put(url, method);
                System.out.println("mapped " + url + "," + method);
            }
        }
    }

    public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException {
        this.doPost(req, res);
    }

    /**
     * 业务处理
     *
     * @param req
     * @param res
     */
    public void doPost(HttpServletRequest req, HttpServletResponse res) throws IOException {
        try {
            //开始匹配到对应的方法
            doDispatch(req, res);
        } catch (Exception e) {
            //如果匹配过程中出现异常,将异常值打印出去
            res.getWriter().write("500 Exception, Details: \r\n"
                    + Arrays.toString(e.getStackTrace()).replaceAll("\\[|\\}]", "")
                    .replaceAll(",\\s", "\r\n"));
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse res) throws IOException {
        if (this.handlerMapping.isEmpty()) {
            return;
        }

        String url = req.getRequestURI();
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");

        if (!this.handlerMapping.containsKey(url)) {
            res.getWriter().write("404 Not Found");
            return;
        }

        Method method = this.handlerMapping.get(url);
        //获取方法的参数列表
        Class<?>[] paramsTypes = method.getParameterTypes();
        //获取请求的参数
        Map<String, String[]> paramterMap = req.getParameterMap();
        //保存参数值
        Object[] paramValues = new Object[paramsTypes.length];
        //方法的参数列表
        for (int i = 0; i < paramsTypes.length; i++) {
            //根据参数名称做某些处理,
            Class parameterType = paramsTypes[i];
            if (parameterType == HttpServletRequest.class) {
                //参数类型已明确,强制转类型
                paramValues[i] = req;
                continue;
            } else if (parameterType == HttpServletResponse.class) {
                paramValues[i] = res;
                continue;
            } else if (parameterType == String.class) {
                for (Map.Entry<String, String[]> param : paramterMap.entrySet()) {
                    String value = Arrays.toString(param.getValue())
                            .replaceAll("\\[|\\]", "")
                            .replaceAll(",\\s", ",");
                    paramValues[i] = value;
                }
            }
        }

        try {
            String beanName = lowerFirstCase(method.getDeclaringClass().getSimpleName());
            //利用反射机制来调用
            method.invoke(this.ioc.get(beanName), paramValues);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

最后添加tomcat并运行,会返回404,没关系,我们没有设置默认页。在输入http://localhost:8080/demo/get?name=ddd即可看到返回数据,方法调用成功。

代码获取github:https://github.com/dwenb/springmvc-demo

本文参考:https://www.jianshu.com/p/f57db8b29be9 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 首先,需要在IDEA中安装Spring Boot插件。可以在IDEA的插件市场中搜索“Spring Boot”,然后安装。 2. 创建一个新的Spring Boot项目。在IDEA的欢迎界面中,选择“Create New Project”,然后选择“Spring Initializr”。在Spring Initializr中,选择项目的基本信息,例如项目名称、包名、项目类型等。然后,选择需要的依赖项,例如Web、JPA、Thymeleaf等。最后,点击“Generate”按钮,生成项目。 3. 在IDEA中打开生成的项目。可以看到项目的结构,包括src/main/java、src/main/resources等目录。其中,src/main/java目录中包含了项目的Java代码,src/main/resources目录中包含了项目的配置文件和静态资源。 4. 编写Spring Boot应用程序。在src/main/java目录中,创建一个新的Java类,例如Application。在Application类中,添加@SpringBootApplication注解,表示这是一个Spring Boot应用程序。然后,编写应用程序的业务逻辑。 5. 运行Spring Boot应用程序。在IDEA中,可以直接运行Spring Boot应用程序。在Application类中,点击右键,选择“Run Application.main()”即可启动应用程序。在启动过程中,可以看到控制台输出的日志信息。 6. 测试Spring Boot应用程序。在IDEA中,可以使用内置的HTTP客户端测试Spring Boot应用程序。在Application类中,点击右键,选择“Run Application.main()”。然后,在IDEA的底部可以看到“Run”窗口。在“Run”窗口中,选择“HTTP Client”选项卡,然后输入HTTP请求的URL和请求参数。点击“Send Request”按钮,即可发送HTTP请求,并查看响应结果。 7. 部署Spring Boot应用程序。在IDEA中,可以使用内置的部署工具将Spring Boot应用程序部署到服务器上。在Application类中,点击右键,选择“Deploy Application”。然后,选择需要部署的服务器和部署路径,点击“Deploy”按钮即可完成部署。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值