相信大家都用过struts或者
spring mvc这样的mvc框架,先来介绍一下mvc吧,
MVC是三个单词的缩写,分别为: 模型(Model),视图(View)和控制Controller)。 MVC模式的目的就是实现Web系统的职能分工。 Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现。 View层用于与用户的交互,通常用JSP来实现。 Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。
mvc带来的好处 ,google一下一大箩筐,这里就不说了。
其实没个mvc底层的实现就是一个大的servlet ,来拦截我们得请求 ,分发到不同处理操作,然后跳转到相应的视图,当然这些都可配置的,mvc这个project我们也会机遇
Java annotation的方式来实现的
我们知道spring 通过java annotation就可以注释一个类为action ,在方法上添加上一个java annotation 就可以配置请求的路径了 ,那么我们得实现也参考这个过程来完成我们要做的事情
①定义请求路径的java annotation
RequestMapping.java
- package com.ajunframework.servlet.annotation;
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Inherited;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- public @interface RequestMapping {
- public String value() default "";
- }
此时请求的路径 ,我们可以做一个解析 ,然后找到你的action类中方法上的注释和你解析出来的路径一致,说名就是这个方法,接着我们利用java反射机制调用这个类得方法,就可以了,接着这个方法会返回一个路径,就是我们跳转的视图返回给我们总的servlet ,就行跳转。
这些功能改怎么实现呢?
首先考虑你返回的视图的路径,其中还有包含的数据怎么办呢?还有就是服务器端跳转还是客户端跳转呢?
此时我们要定义一个视图类,对这些操作属性进行封装,其中包括条状的路径 、展现到页面的数据(这里只是做request范围内的)、跳转方式。
下面是视图类得封装代码:
- package com.ajunframework.servlet.view;
- import com.ajunframework.servlet.constant.DispatchActionConstant;
- public class View {
- private String url;
- private String dispathAction = DispatchActionConstant.FORWARD;
- public View(String url) {
- this.url = url;
- }
- public View(String url,String name,Object value) {
- this.url = url;
- ViewData view = new ViewData();
- view.put(name, value);
- }
- public View(String url,String name,String dispathAction ,Object value) {
- this.dispathAction = dispathAction;
- this.url = url;
- ViewData view = new ViewData();
- view.put(name, value);
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public String getDispathAction() {
- return dispathAction;
- }
- public void setDispathAction(String dispathAction) {
- this.dispathAction = dispathAction;
- }
- }
request范围的数据存储类ViewData.java
- package com.ajunframework.servlet.view;
- import javax.servlet.http.HttpServletRequest;
- import com.ajunframework.servlet.WebContext;
- public class ViewData {
- private HttpServletRequest request;
- public ViewData() {
- initRequestAndResponse();
- }
- private void initRequestAndResponse(){
- this.request = WebContext.requestHodler.get();
- }
- public void put(String name,Object value){
- this.request.setAttribute(name, value);
- }
- }
还有就是我们在每次请求的时候,到达action里的时候 我们会用ViewData.put()往request中存数据,而action中并没有request的情况如何处理呢?
下面我提供一个在进入action之前进行初始化request的类WebContext.java
- package com.ajunframework.servlet;
- import javax.servlet.ServletContext;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- public class WebContext {
- public static ThreadLocal<HttpServletRequest> requestHodler = new ThreadLocal<HttpServletRequest>();
- public HttpServletRequest getRequest(){
- return requestHodler.get();
- }
- public HttpSession getSession(){
- return requestHodler.get().getSession();
- }
- public ServletContext getServletContext(){
- return requestHodler.get().getSession().getServletContext();
- }
- }
通过这个类 ,你可以当前请求的request或者session相关请求类的实例变量,线程间互不干扰的,因为用到了ThreadLocal这个类。
下面来介绍一下servlet的实现,这是无论是get post请求都会调用我封转的方法 ,这个方法,会根据你请求的url,找到你对象的action ,然后调用其中方法注释和改url配置的方法,同事返回View视图类,接着根据View中的路径,返回到相应的视图。
为了方便这里我用到了我们写的ioc,用于在servlet初始化的过程中,实例化和注入相关的class,供我们调用。这里耦合在一起了 ,不是很好。。。
DispatchServlet.java
- package com.ajunframework.servlet;
- import java.io.IOException;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import javax.servlet.ServletConfig;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import com.ajunframework.beans.applicationContext.AnnotationClassPathApplicationContext;
- import com.ajunframework.beans.factory.AnnotationBeanFactory;
- import com.ajunframework.beans.factory.RequestMapingMap;
- import com.ajunframework.beans.utils.BeanUtils;
- import com.ajunframework.servlet.annotation.RequestMapping;
- import com.ajunframework.servlet.constant.DispatchActionConstant;
- import com.ajunframework.servlet.view.View;
- public class DispatchServlet extends HttpServlet {
- private static final long serialVersionUID = 5325307163972641802L;
- @Override
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
-
- AnnotationClassPathApplicationContext.getAnnotationClassPathApplicationContext().init();
- }
- public void doGet(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.excute(request, response);
- }
- public void doPost(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
- this.excute(request, response);
- }
- private void excute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
- WebContext.requestHodler.set(request);
- String lasturl = pareRequestURI(request);
- String className = RequestMapingMap.getRequesetMap().get(lasturl);
- Object actionClass = AnnotationBeanFactory.getBeanFactory().getBean(className);
- Method [] methods = BeanUtils.findDeclaredMethods(actionClass.getClass());
- Method method = null;
- for(Method m:methods){
- if(m.isAnnotationPresent(RequestMapping.class)){
- String anoPath = m.getAnnotation(RequestMapping.class).value();
- if(anoPath!=null && !"".equals(anoPath.trim()) && lasturl.equals(anoPath.trim())){
- method = m;
- break;
- }
- }
- }
- try {
- if(method!=null){
- View view = (View)method.invoke(actionClass, request,response);
- if(view.getDispathAction().equals(DispatchActionConstant.FORWARD)){
- request.getRequestDispatcher(view.getUrl()).forward(request, response);
- }else if(view.getDispathAction().equals(DispatchActionConstant.REDIRECT)){
- response.sendRedirect(view.getUrl());
- }else{
- request.getRequestDispatcher(view.getUrl()).forward(request, response);
- }
- }
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- private String pareRequestURI(HttpServletRequest request){
- String path = request.getContextPath()+"/";
- String requestUri = request.getRequestURI();
- String midUrl = requestUri.replaceFirst(path, "");
- String lasturl = midUrl.substring(0, midUrl.lastIndexOf("."));
- return lasturl;
- }
- }
web.xml对这个servlet的配置
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.5"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
- http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
- <servlet>
- <servlet-name>DispatchServlet</servlet-name>
- <servlet-class>com.ajunframework.servlet.DispatchServlet</servlet-class>
- </servlet>
- <servlet-mapping>
- <servlet-name>DispatchServlet</servlet-name>
- <url-pattern>*.ajun</url-pattern>
- </servlet-mapping>
- <welcome-file-list>
- <welcome-file>index.jsp</welcome-file>
- </welcome-file-list>
- </web-app>
这里还用到了一个跳转方式的常量类介绍给大家DispatchActionConstant.java
- package com.ajunframework.servlet;
- public class DispatchActionConstant {
- public static String FORWARD = "forward";
- public static String REDIRECT = "redirect";
- }
现在这个简单的mvc已经实现了,下一节做个测试。。。