手写Springmvc框架

Springmvc的处理流程

 

 

1、自定义注解

元注解

元注解就是用来解释我们自定义注解。结合我们xml文档的dtd.schemel约束

@Target:作用早我们的类上,变量上,方法,指定我们的注解是作用在什么目标上

(类上,变量上,方法)。

@Retention:用来描述我们自定义注解的生命周期

SOURCE:源文件,CLASS:编译时期

RUNTIME:运行时期(对照我们的Exception来比较理解)

@Documented:javadoc此类的工具的文档化,将其中的注释生成对应的API

 

自定义注解:

针对我们的springmvc

@Controller:控制类上的注解

@Service:标注该bean类是service

@RequestMapping:映射请求地址

@Quallifier:注入bean类的功能

 

 

代码

 

1. 编写web.xml

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

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

            http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

version="3.0">

<servlet>

<servlet-name>MySpringMVC</servlet-name>

<servlet-class>com.dongyu.servlet.DispatcherServlet</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>common.properties</param-value>

</init-param>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>MySpringMVC</servlet-name>

<url-pattern>/*</url-pattern>

</servlet-mapping>

</web-app>

 

2. 编写common.properties文件

scanPackage=com.dongyu

 

3. 编写自定义注解

/**

 * 自定义控制层注解

 * @author mama

 *

 */

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Controller {

String value() default "";

}

 

/**

 * 注入实例

 * @author mama

 *

 */

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Qualifier {

String value() default "";

}

/**

 * 自定义方法注解

 * @author mama

 *

 */

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface RequestMapping {

//表示访问该方法的url

String value() default "";

}

 

/**

 * 自定义业务层注解

 * @author mama

 *

 */

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Service {

String value() default "";

}

 

4. 编写Controller

@Controller("dongYu")

public class DongYuController {

 

@Qualifier("dongYuServiceImpl")

private DongYuService dongYuService;

@RequestMapping("insert")

public String insert(HttpServletRequest request,HttpServletResponse response,String url) {

dongYuService.insert(null);

return null;

}

@RequestMapping("delete")

public String delete(HttpServletRequest request,HttpServletResponse response,String url) {

dongYuService.delete(null);

return null;

}

@RequestMapping("update")

public String update(HttpServletRequest request,HttpServletResponse response,String url) {

dongYuService.update(null);

return null;

}

@RequestMapping("select")

public String select(HttpServletRequest request,HttpServletResponse response,String url) {

dongYuService.select(null);

return null;

}

}

5. 编写Service

public interface DongYuService {

int insert(Map map);

int delete(Map map);

int update(Map map);

int select(Map map);

}

 

@Service("dongYuServiceImpl")

public class DongYuServiceImpl implements DongYuService{

 

public int insert(Map map) {

System.out.println("----------insert");

return 0;

}

 

public int delete(Map map) {

System.out.println("----------delete");

return 0;

}

 

public int update(Map map) {

System.out.println("----------update");

return 0;

}

 

public int select(Map map) {

System.out.println("----------select");

return 0;

}

 

}

 

6. 编写servlet

/**

 * 核心控制类?

 * @author mama

 *

 */

@WebServlet("/DispatcherServlet")

public class DispatcherServlet extends HttpServlet{

 private Properties properties = new Properties();

//将我们扫描的权限定类名放入集合类

private List<String> packeNames=new ArrayList<String>();

//定义一个注解属性i,对应各层对象实例Map

Map<String,Object> instanceMaps=new HashMap<String,Object>();

//请求url对应的method对象

Map<String,Object> hanlderMaps=new HashMap<String,Object>();

 @Override

public void init(ServletConfig config) throws ServletException {

/**

 * 扫描基础包上面的注解:com.dongyu

 * 扫描基础包之后,拿到全限定名称? ---包名+类名称?

 * com/dongyu/service/DongYuServiceImpl.java

 * 替换上面类?/

 * com.dongyu.service.DongYuServiceImpl.java

 * 拿到实例

 * 将实例注入各层bean变量

 */

 

 /**

  * 扫描全包

  * 找到实例

  * 通过我们的方法连接来拿到相应的处理类实例

  *

  */

 

 //1.加载配置文件

 doLoadConfig(config.getInitParameter("contextConfigLocation"));

 //2.初始化所有相关联的类,扫描用户设定的包下面所有的类

 scanBase(properties.getProperty("scanPackage"));

 try {

  //3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v  beanName-bean) beanName默认是首字母小写

filterAndInstance();

springIoc();

  //4.初始化HandlerMapping(将urlmethod对应上)

halderMaps();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

}

 

 

 /**

  * 扫描配置文件

  * @param initParameter

  */

 private void doLoadConfig(String location) {

//把web.xml中的contextConfigLocation对应value值的文件加载到流里面

   InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location);

   try {

     //用Properties文件加载文件里的内容

     properties.load(resourceAsStream);

   } catch (IOException e) {

     e.printStackTrace();

   }finally {

     //关流

     if(null!=resourceAsStream){

       try {

         resourceAsStream.close();

       } catch (IOException e) {

         e.printStackTrace();

       }

     }

   }

}

 

 

/**

  * 通过url找到相应的method对象进行处理

  */

private void halderMaps() throws Exception{

if(instanceMaps.size()<=0) {

return ;

}

//存的实例是有控制层和service�?

for (Map.Entry<String, Object> entry : instanceMaps.entrySet()) {

if(entry.getValue().getClass().isAnnotationPresent(Controller.class)) {

String baseURL=((Controller)entry.getValue().getClass().getAnnotation(Controller.class)).value();

Method[] controolerMethods = entry.getValue().getClass().getMethods();

for (Method controolerMethod : controolerMethods) {

if(controolerMethod.isAnnotationPresent(RequestMapping.class)) {

//在方法上游RequestMapping注解时,我们才做处理

String methodURL=((RequestMapping)controolerMethod.getAnnotation(RequestMapping.class)).value();

hanlderMaps.put("/"+baseURL+"/"+methodURL, controolerMethod);

}else {

continue;

}

}

}

}

}

 

 

 

/**

  * 把实例注入到ioc容器中

 * @throws Exception

 * @throws IllegalArgumentException

  */

private void springIoc() throws IllegalArgumentException, Exception {

if(instanceMaps.size()<=0) {

return ;

}

for (Map.Entry<String, Object> entry : instanceMaps.entrySet()) {

Field[] fields = entry.getValue().getClass().getDeclaredFields();

for (Field field : fields) {

if(field.isAnnotationPresent(Qualifier.class)) {

//IOC注入

String value = ((Qualifier)field.getAnnotation(Qualifier.class)).value();

field.setAccessible(true);

field.set(entry.getValue(),instanceMaps.get(value));

}else {

continue;

}

}

}

}

 

 

 

 

/**

  * 扫描全包的方法

  */

private void scanBase(String basePackage){

 URL url=this.getClass().getClassLoader().getResource("/"+basePackage.replaceAll("\\.", "/"));

 //拿到该路径下面的文件夹,以及文件

 String pathFile = url.getFile();

 //最终的目的是将这个路径封住成一个File

 File file=new File(pathFile);

 String[] files = file.list();

 for (String path : files) {

//再次构造成一个file类

 File eachFile=new File(pathFile+path);

 if(eachFile.isDirectory()) {

 //递归应用scanBase()

 //System.out.println("扫描到的类"+basePackage+"."+eachFile.getName());

 scanBase(basePackage+"."+eachFile.getName());

 }else if (eachFile.isFile()) {

//表示扫描到的是一个实在文件?

 System.out.println("扫描到的类"+basePackage+"."+eachFile.getName());

 packeNames.add(basePackage+"."+eachFile.getName());

}

}

 

}

/**

 * 将全包名称替换成一个路径

 */

private String replacePath(String path) {

return path.replaceAll("\\.", "/");

}

 /**

  * 拦截方法请求,然后在对应请求地址找到对应的handler实例

  */

 private void filterAndInstance() throws Exception{

//判断集合里面是否有实例

 if(packeNames.size()<=0) {

 return;

 }

 for (String string : packeNames) {

Class ccName=Class.forName(string.replace(".class", ""));

if(ccName.isAnnotationPresent(Controller.class)) {

Object instance = ccName.newInstance();

//将实例装入Map key

Controller controllerAnController = (Controller)ccName.getAnnotation(Controller.class);

//通过注解对象拿到属性值 xml: key:beanID  value:class=com.

String key=controllerAnController.value();

//通过注解的key找到对应的bean的实例

instanceMaps.put(key, instance);

}else if (ccName.isAnnotationPresent(Service.class)) {

Object instance = ccName.newInstance();

//将实例装入Map key

Service serviceAnController = (Service)ccName.getAnnotation(Service.class);

//通过注解对象拿到属性值 xml: key:beanID  value:class=com.

String key=serviceAnController.value();

//通过注解的key找到对应的bean的实例

instanceMaps.put(key, instance);

}else {

//没有注解

continue;

}

 }

}

 

@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 {

String uri=req.getRequestURI();

String projectNamePath = req.getContextPath();

//baseURL+methodURL

String path = uri.replace(projectNamePath, "");

//方法对象

Method method=(Method) hanlderMaps.get(path);

PrintWriter writer = resp.getWriter();

if(method==null) {

writer.write("您访问的地址不存在");

return;

}

//localhost:8080/springmvc/dongYu/insert

String className=uri.split("/")[2];

DongYuController dn=(DongYuController)instanceMaps.get(className);

try {

method.invoke(dn, new Object[] {req,resp,null});

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

 

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
手写Spring MVC是指自己实现一个简单的Spring MVC框架,而不是使用官方提供的Spring MVC框架。在手写Spring MVC时,你需要实现以下几个关键部分: 1. 创建一个前端控制器(Front Controller):前端控制器是整个请求处理过程的入口点,负责接收请求并进行路由。你可以使用Servlet作为前端控制器,接收所有的HTTP请求,并将它们分发给相应的控制器。 2. 定义控制器类:控制器类负责处理特定URL的请求,并根据请求参数进行相应的处理。你可以使用注解(如@RequestMapping)来定义控制器类和方法的映射关系。 3. 实现视图解析器(View Resolver):视图解析器负责解析控制器返回的逻辑视图名,并将其转换为具体的视图对象或视图模板。你可以使用模板引擎(如Thymeleaf、Freemarker等)来渲染动态内容。 4. 注册控制器和视图解析器:在前端控制器中,你需要注册所有的控制器类和视图解析器,以便能够正确地处理请求和渲染视图。 5. 处理请求和响应:在控制器中,你需要编相应的方法来处理请求,并根据业务逻辑生成响应。你可以使用HttpServletRequest和HttpServletResponse对象来访问请求参数和生成响应。 6. 配置URL映射:你需要在配置文件中配置URL与控制器方法的映射关系,以便能够正确地将请求分发给对应的控制器。 手写Spring MVC的过程可以帮助你更好地理解Spring MVC框架的工作原理和核心组件。但请注意,手写一个完整的Spring MVC框架可能会比较繁琐和复杂,特别是对于初学者来说。因此,如果你只是想学习Spring MVC的基本原理和用法,我建议你先阅读官方文档或参考一些教程来快速入门。如果你确实有兴趣手写Spring MVC,你可以参考引用中的博客文章,里面提供了一个手写Spring MVC框架的实现示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [手写 springmvc](https://download.csdn.net/download/knight_black_bob/10207699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringMvc手写简单实现篇 - MVC完结篇](https://blog.csdn.net/qq_35551875/article/details/121811048)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值