欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

手写springmvc

程序员文章站 2022-07-15 11:22:09
...
  1. 创建一个maven项目 war
  2. 导入dom4jar包
  3. 配置web.xml
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>base.web.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>

4.配置DispatcherServlet

package base.web;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import base.common.Handler;
import base.common.HandlerMapping;


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

	//HandlerMapping负责提供请求路径与处理器的对应关系
	private HandlerMapping handlerMapping;

	@Override
	/**
	 * 读取配置文件(smartmvc.xml)中的处理器的
	 * 配置信息,然后将处理器实例化并存放到一个
	 * 集合里面。接下来,将这个集合交给
	 * HandlerMapping来处理。
	 * 注:
	 * HandlerMapping处理流程:
	 * (通过java反射读取处理器中的
	 * @RequestMapping注解信息,建立请求路径与处理器
	 * 方法的对应关系,比如 "/hello.do"应该由
	 * HelloController的hello方法来处理)。
	 *
	 */
	public void init() throws ServletException {
		/*
		 * 使用dom4j读取配置文件的内容
		 */
		SAXReader reader =
				new SAXReader();
		InputStream ins =
				getClass().getClassLoader()
				.getResourceAsStream(
						"smartmvc.xml");
		try {
			//解析配置文件
			Document doc = reader.read(ins);
			//找到根节点
			Element root = doc.getRootElement();
			//找到根节点下面的所有的子节点
			List<Element> eles = root.elements();
			//遍历所有子节点
			List beans = new ArrayList();
			for(Element ele : eles){
				//读取class属性值
				String className =
					ele.attributeValue("class");
				System.out.println("className: "
					+ className);
				//将处理器实例化
				Object bean =
						Class.forName(className)
						.newInstance();
				//将处理器实例添加到集合里面。
				beans.add(bean);
			}
			System.out.println("beans:" + beans);

			//将包含有处理器实例的集合给
			//HandlerMapping来处理。
			handlerMapping = new HandlerMapping();
			handlerMapping.process(beans);

		} catch (Exception e) {
			e.printStackTrace();
			throw new ServletException(e);
		}
	}



	protected void service(
			HttpServletRequest request,
			HttpServletResponse response)
					throws ServletException,
					IOException {
		//获得请求资源路径
		String uri = request.getRequestURI();
		//获得应用名
		String contextPath =
				request.getContextPath();
		//截取请求资源路径的一部分
		String path =
				uri.substring(
						contextPath.length());
		System.out.println("path:" + path);

		//依据请求路径(path)找到对应的处理器来处理
		Handler handler =
				handlerMapping.getHandler(path);
		System.out.println("handler:"
				+ handler);

		//获得要调用的Method对象
		Method mh = handler.getMh();
		//获得处理器实例
		Object bean = handler.getObj();
		//returnVal是方法的返回值
		Object returnVal = null;
		try {

			/*
			 * 调用处理器的方法:
			 * 需要查看处理器方法带不带参数,如果
			 * 带有参数,需要给参数赋值,然后才
			 * 能调用。
			 */
			Class[] types = mh.getParameterTypes();
			if(types.length > 0){
				//带有参数的方法
				Object[] params =
						new Object[types.length];
				for(int i = 0; i < types.length; i ++){
					if(types[i] ==
							HttpServletRequest.class){
						params[i] = request;
					}
					if(types[i] ==
							HttpServletResponse.class){
						params[i] = response;
					}
				}
				//调用带参数的方法
				returnVal = mh.invoke(bean, params);
			}else{
				//调用不带参的方法
				returnVal = mh.invoke(bean);
			}
			System.out.println("returnVal:"
			+ returnVal);
			/*
			 * 看视图名是否以"redirect:"开头,
			 * 如果是,则重定向;否则转发。
			 */
			String viewName = returnVal.toString();
			if(viewName.startsWith("redirect:")){
				//重定向

				//生成重定向地址
				String redirectPath =
					contextPath + "/"
				+ viewName.substring(
						"redirect:".length());
				response.sendRedirect(redirectPath);
			}else{
				//转发

				//将视图名转换成对应的jsp
				String jspPath =
						"/WEB-INF/" + viewName
						+ ".jsp";
				request.getRequestDispatcher(
						jspPath).forward(
								request, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServletException(e);
		}
	}

}

5.写注解@RequestMapping

package base.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
	public String value();
}

6.添加处理器(比如LoginController)
在该处理器里面,方法前添加@RequestMapping注解。
方法的返回值是视图名。

package demo.controller;

import javax.servlet.http.HttpServletRequest;

import base.annotation.RequestMapping;

public class LoginController {
	@RequestMapping("/toLogin.do")
	public String toLogin(){
		System.out.println(
				"LoginController的toLogin方法");
		return "login";
	}
	@RequestMapping("/login.do")
	public String login(
			HttpServletRequest request){
		System.out.println("处理登录请求");
		
		String username = 
				request.getParameter("username");
		String pwd = 
				request.getParameter("pwd");
		System.out.println("username:" 
				+ username + " pwd:" + pwd);
		
		if("Tom".equals(username) 
				&& "test".equals(pwd)){
			//登录成功,重定向到用户列表
			
			//视图名前面有"redirect:",表示
			//重定向到某个地址。
			return "redirect:toList.do";
		}else{
			//登录失败,转发到登录页面,并提示用户
			request.setAttribute("login_failed",
					"用户名或密码错误");
			return "login";
		}
		
		
	}	
	@RequestMapping("/toList.do")
	public String toList(){
		return "listUser";
	}
}

7.在resource下添加smartmvc.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans>
	<!-- 
		配置处理器
	 -->
	<bean class="demo.controller.LoginController"/>
	
</beans>

8.添加jsp。
注意jsp文件名应该符合 “/WEB-INF/” + 视图名 + “.jsp”。

login.jsp

<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body style="font-size:30px;">
	<form action="login.do" method="post">
		<fieldset>
			<legend>登录</legend>
			用户名:<input name="username"/>
			${login_failed}
			<br/>
			密码:<input type="password" 
				name="pwd"/><br/>
			<input type="submit" value="确定"/>
		</fieldset>
	</form>
</body>
</html>

listUsr.jsp

<%@ page contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<html>
<head>
<title>Insert title here</title>
</head>
<body style="font-size:30px;">
	用户列表
</body>
</html>