手写springmvc
程序员文章站
2022-07-15 11:22:09
...
- 创建一个maven项目 war
- 导入dom4jar包
- 配置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>