springmvc执行流程:
一 .创建前端控制器
public class MyDispatcherServlet extends HttpServlet
属性:
//配置文件
private Properties configProperties = null;
//spring mvc 的ioc容器
private ConcurrentHashMap<String,Object> ioc = null;
//springmvc的 地址映射与类之间的关联
// key:地址 URI value: 哪个类
private ConcurrentHashMap<String,Object> beanUrl = null;
//springmvc的 地址映射的 对应的要执行的方法是哪个
private ConcurrentHashMap<String,String> beanMethod = null;
初始化操作
1.加载配置文件
2.完成ioc容器的初始化操作
3.完成地址映射 的两个map的初始化
/**
* 容器初始化的操作 加载配置文件,这里为了方便就用 properties 文件
* @param config
* @throws ServletException
*/
@Override
public void init(ServletConfig config) throws ServletException
{
System.out.println ("初始化");
//读取配置文件
loadConfig(config);
//实例化ioc容器,地址映射和方法映射
this.ioc = new ConcurrentHashMap<> ();
this.beanUrl = new ConcurrentHashMap<> ();
this.beanMethod = new ConcurrentHashMap<> ();
//从properties获取包名 然后扫描该包下的所有类 此时ioc容器已经加载完毕了
loadAnnotationClass(this.configProperties.getProperty ("packageName"));
//加下来就要初始化 beanUrl 和 beanMethod
initBeanUrlAndBeanMethod();
printAll ();
}
/**
* 加载 properties 配置文件
* @param config
*/
private void loadConfig(ServletConfig config)
{
//获取文件地址 classpath
String configurationFile = config.getInitParameter ("contextConfigLocation");
System.out.println ("configurationFile:"+configurationFile);
//加载配置文件
this.configProperties = new Properties ();
configurationFile = configurationFile.substring (configurationFile.indexOf (":")+1,configurationFile.length ());
InputStream is = this.getClass ().getClassLoader ().getResourceAsStream (configurationFile);
try
{
this.configProperties.load (is);
} catch (IOException e)
{
e.printStackTrace ();
}finally
{
if(null != is)
{
try
{ //关闭流
is.close ();
} catch (IOException e)
{
e.printStackTrace ();
}
}
}
}
/**
* 加载 包下的所有类 (加了MyController注解的)
* @return
*/
private void loadAnnotationClass(String packageName)
{
try
{
//获取该报下的所有类,不包含接口 不管加没加注解都获取到
List<Class<?>> classList = MyClassUtils.getClasses (packageName);
//返回 加了MyController注解的 类
List<Class<?>> annoClasses = findClassIsPreAnnoctation (classList);
//实例化,加载到 ioc 中
newInstanceBean (annoClasses);
} catch (Exception e)
{
e.printStackTrace ();
}
}
/**
* 返回被注解申明的 class
*
* @param classes
* @return
*/
private List<Class<?>> findClassIsPreAnnoctation(List<Class<?>> classes)
{
//加了注解的集合
List<Class<?>> annoctationPresentClasses = new ArrayList<> ();
for (Class clazz : classes)
{
//MyController
if (clazz.isAnnotationPresent (MyController.class))
{
//添加到容器中
annoctationPresentClasses.add (clazz);
continue;
}
}
return annoctationPresentClasses;
}
/**
* 反射实例化bean
*/
private void newInstanceBean(List<Class<?>> anncotaionedClasses) throws Exception
{
//没有空参构造器的 clazz 等有空参构造器的初始化完了再初始化
List<Class<?>> nullConstructor = new ArrayList<> ();
for (Class<?> clazz : anncotaionedClasses)
{
//判断是否有空参构造方法,有的话直接初始化,没有的话放置到后面
Constructor constructor = clazz.getConstructor ();
if (constructor == null)
{
anncotaionedClasses.remove (clazz);
nullConstructor.add (clazz);
continue;
}
//反射实例化
Object o = clazz.newInstance ();
MyController declaredAnnotation = clazz.getDeclaredAnnotation (MyController.class);
//如果名字为空,默认为首字母小写
if ("".equals (declaredAnnotation.value ()))
{
// 获取 类名即可
String className = toLowerCaseFirstOne (clazz.getSimpleName ());
String beanId = toLowerCaseFirstOne (className);
//添加到ioc容器中
ioc.put (beanId, o);
continue;
}
else //代表 用户自定义类名的id
{
String beanId=declaredAnnotation.value ();
ioc.put (beanId,o);
}
}
}
```java
/**
* 对beanUrl 和 beanMethod 初始化
*/
private void initBeanUrlAndBeanMethod()
{
if(ioc == null)
{
return;
}
Set<Map.Entry<String, Object>> entries = this.ioc.entrySet ();
for(Map.Entry entry : entries)
{
//得到ioc中每一个bean对象
Object bean = entry.getValue ();
//第一步判断类上是否有加有 MyRequestMapping 注解
MyRequestMapping mapping = bean.getClass ().getDeclaredAnnotation (MyRequestMapping.class);
String classMapping = "";
String methodMapping = "";
//类上的不为空
if(mapping != null)
{
classMapping = mapping.value ();
}
//遍历每个方法,判断方法上是否加有 RequestMapping
Method[] methods = bean.getClass ().getMethods ();
//地址映射id
String url="";
for(Method method : methods)
{
MyRequestMapping methoAnnotation = method.getDeclaredAnnotation (MyRequestMapping.class);
if(methoAnnotation != null) //代表注解上加有MyRequestmapping
{
methodMapping = methoAnnotation.value ();
//最后判断 如果方法上的url 没有地址 则不添加 否者 添加进去
if(StringUtils.isNotBlank (methodMapping))
{
if(classMapping.indexOf ("/")!=0 && StringUtils.isNotBlank (classMapping))
{
classMapping = "/"+classMapping;
}
if(methodMapping.indexOf ("/")!=0 && StringUtils.isNotBlank (methodMapping))
{
methodMapping = "/"+methodMapping;
}
url = classMapping + methodMapping;
beanUrl.put (url,bean);
beanMethod.put (url,method.getName ());
}
}
}
}
}
// 首字母转小写
public static String toLowerCaseFirstOne(String s)
{
if (Character.isLowerCase (s.charAt (0)))
{
return s;
}
else
{
return (new StringBuilder ()).append (Character.toLowerCase (s.charAt (0))).append (s.substring (1)).toString ();
}
}
处理 用户端的请求
这里重写了doget和dopost方法
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.doPost (request,response);
}
/**
* 真正的实现 接收请求和响应请求
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doDispatachMethod(request,response);
}
/**
* 实现 地址映射 请求 执行相应的方法
*/
private void doDispatachMethod(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
{
//得到请求的地址 是端口号后面的地址
String requestURI = request.getRequestURI ();
//向 地址映射的 beanUrl 查找类
Object bean = beanUrl.get (requestURI);
//如果为空,代表没有 这个地址映射
if(bean == null)
{
response.getWriter ().println ("Sorry 404 你访问的页面不存在!");
return;
}
//后面代表不为空 得到 地址映射的方法
String methodName = this.beanMethod.get (requestURI);
if(StringUtils.isEmpty (methodName))
{
response.getWriter ().println ("Sorry 404 你访问的页面不存在!");
return;
}
/**
* 执行方法 得到class 反射执行
*/
Class<?> beanClass = bean.getClass ();
Object result=invokeBeanMethod(beanClass,methodName,bean);
//最后 展示视图
viewResolver(result,request,response);
}
/**
* 最后根据返回值 处理视图跳转
* @param result
* @param request
* @param response
*/
private void viewResolver(Object result, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 获取后缀信息
String suffix = ".jsp";
// 页面目录地址
String prefix = "/";
String pageName=(String)result;
String path = prefix + pageName + suffix;
if(pageName.contains ("redirect"))
{
response.sendRedirect (path);
}
else //默认请求转发
{
request.getRequestDispatcher (path).forward (request,response);
}
}
最终效果
@MyController
@MyRequestMapping ("/product")
public class ProductController
{
@MyRequestMapping("addProduct")
public String addProduct()
{
return "wZF";
}
@MyRequestMapping("/updateProduct")
public void updateProduct()
{
}
}