使用注解简单实现SpringMVC
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">
<display-name>WTK Web Application</display-name>
<servlet>
<servlet-name>WTKSpringMVC</servlet-name>
<!--<servlet-class>com.wtk.mvcframework.servlet.WTKDispatcherServlet</servlet-class>-->
<servlet-class>com.wtk.springmvc.servlet.WTKDispatcherServlet</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>WTKSpringMVC</servlet-name>
<servlet-name>WTKSpringMVC</servlet-name>
<!--"/" 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。-->
<!-- " /*" 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2:自定义controller注解,
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WTKController {
/**
* 表示给controller注册别名
* @return
*/
String value() default "";
}
3:自定义RequestMapping注解,
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WTKRequestMapping {
/**
* @return
*/
String value() default "";
}
4:自定义前端控制器,和web.xml匹配
/**
*自定义前端控制器
* 1:创建一个前端控制器(WTKDispatcherServlet) 拦截所有的请求(springmvc 基于servlet实现)
* 2:初始化操作,重写 servlet init方法
* 2.1:将扫包范围的所有类,注入到springmvc容器里,存放到map集合中,key为默认类名小写,value为对象
* 2.2:将url映射和方法进行关联
* 2.2.1:判断方法上是否有注解,使用java反射机制循环遍历方法,判断方法上是否有注解,进行封装url和方法对应 存入到map集合
* 3:处理请求,重写GET/POST方法
* 3.1:获取请求url,从urlbean集合获取实例对象,获取成功实例对象后,调用urlMether集合获取请求方法名称,使用反射机制执行,
*
*
* */
public class WTKDispatcherServlet extends HttpServlet{
//springmvc 容器对象key : 类名id,value 对象
private ConcurrentHashMap<String,Object> springmvcBean = new ConcurrentHashMap<String, Object>();
//springmvc 容器对象,key 请求地址,value 类
private ConcurrentHashMap<String,Object> urlBeans = new ConcurrentHashMap<String, Object>();
//springmvc容器对象 key:请求地址,value 方法名
private ConcurrentHashMap<String,String> urlMethods = new ConcurrentHashMap<String, String>();
@Override
public void init() throws ServletException{
//1:获取当前包下的所有类
List<Class<?>> classes = ClassUtil.getClasses("com.wtk.springmvc.controller");
//2:将扫包的范围内所有的类,注入到springMVC容器里面,存放在Map集合中,key默认为类名小写,value 为对象
try {
findClassMVCAnnotation(classes);
}catch (Exception e){
}
//3:将url映射和方法进行关联
handlerMapping();
}
public void findClassMVCAnnotation(List<Class<?>> classes) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
for(Class<?> classInof : classes){
//判断类上是否有加注解
WTKController wtkController = classInof.getDeclaredAnnotation(WTKController.class);
if(wtkController != null){
//默认类名为小写
String beanId = ClassUtil.toLowerCaseFirstOne(classInof.getSimpleName());
Object object = ClassUtil.newInstance(classInof);
springmvcBean.put(beanId,object);
}
}
}
//3:将url映射和方法进行关联
public void handlerMapping(){
//1:遍历springmv Bean容器,判断类上是否有url映射路径
for (Map.Entry<String,Object> mvcBean : springmvcBean.entrySet()){
//遍历所有的方法上是否有url映射注解
Object object = mvcBean.getValue();
//3判断类上是否加上了url映射注解
Class<? extends Object> classInfo = object.getClass();
WTKRequestMapping declareAnnotation = classInfo.getDeclaredAnnotation(WTKRequestMapping.class);
String beaseUrl = "";
if(declareAnnotation != null){
//获取类上的url映射地址
beaseUrl = declareAnnotation.value();
}
Method[] declaresMethods = classInfo.getDeclaredMethods();
for (Method method : declaresMethods){
//判断方法上是否加url映射地址
WTKRequestMapping wtkRequestMapping = method.getDeclaredAnnotation(WTKRequestMapping.class);
if(wtkRequestMapping!=null){
String methodUrl = beaseUrl + wtkRequestMapping.value();
//springmvc容器对象 key:请求地址,value:类
urlBeans.put(methodUrl,object);
//springmc 容器对象,key:请求地址,value: 方法名称
urlMethods.put(methodUrl,method.getName());
}
}
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getRequestURI());
doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1:获取请求URL
String requestURL = req.getRequestURI();
if (StringUtils.isEmpty(requestURL)) {
return;
}
//2:从map集合中获取控制对象
Object object = urlBeans.get(requestURL);
if(object == null){
resp.getWriter().println("not foun 404 url");
return;
}
//3:使用url地址获取方法
String methodName = urlMethods.get(requestURL);
if(StringUtils.isEmpty(methodName)){
resp.getWriter().println("not found method");
}
//4:使用java的反射机制调用方法
String resultPage = (String) methodInvoke(object,methodName);
//5:使用java的反射机制获取方法返回结果
extResourceViewResolver(resultPage,req,resp);
//6:调用视图转换器渲染给页面展示
}
private void extResourceViewResolver(String pageName,HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException {
// 根路径
String prefix = "/";
String suffix = ".jsp";
req.getRequestDispatcher(prefix + pageName + suffix).forward(req, res);
}
private Object methodInvoke(Object object,String methodName){
try {
Class<? extends Object> clseeInof = object.getClass();
Method method = clseeInof.getMethod(methodName);
Object result = method.invoke(object);
return result;
} catch (Exception e) {
return null;
}
}
}
5:controller实现
@WTKController
@WTKRequestMapping("/wtk")
public class WtkIndexController {
@WTKRequestMapping("/test")
public String test(){
System.out.println("手写springmvc框架。。。。");
return "indexs";
}
}
6:遇到的问题
(1)在web.xml配置文件中因为在servlet配置的是"/*"导致返回jsp时候会跳入DispatcherServlet导致无法跳入页面,问题找了很久。
<servlet-mapping>
<servlet-name>WTKSpringMVC</servlet-name>
<!--"/" 不会匹配到*.jsp,即:*.jsp不会进入spring的 DispatcherServlet类 。-->
<!-- " /*" 会匹配*.jsp,会出现返回jsp视图时再次进入spring的DispatcherServlet 类,导致找不到对应的controller所以报404错。-->
<url-pattern>/</url-pattern>
</servlet-mapping>
该内容大部分借鉴蚂蚁课堂,如有侵权请指出!!!
如有错误,请指出