写在前面
本文看下如何定义MVC部分内容。
1:正文
首先定义requestmapping注解,映射url->处理方法:
java
@Target(value={ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
String value() default "";
}
简单期间,这里暂时只支持用在方法上,spring mvc是支持同时用在类和方法上的,知道即可。接着我们还要定义DispatcherServlet作为拦截web请求的入口(只保留核心代码):
java
// com.hc.minispring.web.v2.DispatcherServlet
public class DispatcherServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
sContextConfigLocation = config.getInitParameter("contextConfigLocation");
URL xmlPath = null;
try {
xmlPath = this.getServletContext().getResource(sContextConfigLocation);
} catch (MalformedURLException e) {
e.printStackTrace();
}
// 获取所有要扫描的包
this.packageNames = XmlScanComponentHelper.getNodeValue(xmlPath);
// 刷新bean
Refresh();
}
protected void Refresh() {
// 扫描包,获取所有的controller 实例
initController();
// 初始化url和对应method的映射
initMapping();
}
protected void initController() {
this.controllerNames = scanPackages(this.packageNames);
for (String controllerName : this.controllerNames) {
Object obj = null;
Class<?> clz = null;
try {
clz = Class.forName(controllerName);
this.controllerClasses.put(controllerName,clz);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
obj = clz.newInstance();
this.controllerObjs.put(controllerName, obj);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
protected void initMapping() {
for (String controllerName : this.controllerNames) {
// ...
if(methods!=null){
for(Method method : methods){
// 判断方法上是否使用了@RequestMapping注解,使用了则获取映射的url,以及对应的方法,存储备用
boolean isRequestMapping = method.isAnnotationPresent(RequestMapping.class);
if (isRequestMapping){
String methodName = method.getName();
String urlmapping = method.getAnnotation(RequestMapping.class).value();
// ...
// 存储请求web路径和处理该web路径的方法,将会在doGet方法中使用
this.mappingMethods.put(urlmapping, method);
}
}
}
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String sPath = request.getServletPath();
// ...
try {
// 根据请求路径获取处理方法,反射执行,并返回结果
Method method = this.mappingMethods.get(sPath);
obj = this.mappingObjs.get(sPath);
objResult = method.invoke(obj);
} catch (SecurityException e) {
// ...
}
response.getWriter().append(objResult.toString());
}
}
配置component-scan的配置文件如下:
xml
<?xml version="1.0" encoding="UTF-8" ?>
<components>
<component-scan base-package="com.hc.minispring.web.v2.test" />
</components>
在com.hc.minispring.web.v2.test包中我配置了两个类:
java
public class HelloWorldBean {
@RequestMapping("/test")
public String doTest() {
return "hello world for doGet!";
}
}
public class HelloWorldBean1 {
@RequestMapping("/test1")
public String doTest() {
return "1hello world for doGet!";
}
}
最后配置下web.xml就行了:
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID">
<servlet>
<servlet-name>minisMVC</servlet-name>
<servlet-class>com.hc.minispring.web.v2.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/v2/minisMVC-servletv2.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>minisMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
启动后访问:
C:\Users\dell9020>curl http://localhost:8080/minispring_Web_exploded/test
hello world for doGet!
C:\Users\dell9020>curl http://localhost:8080/minispring_Web_exploded/test1
1hello world for doGet!
C:\Users\dell9020>
这样一个简单的mini springmvc就完成了。这样,应用程序开发人员就不需要关心servlet啥的了,只需要提供一个类似于/WEB-INF/v2/minisMVC-servletv2.xml的配置文件,然后在自定义的component scan路径下写对应的业务代码就可以了。