3.自己动手写Java Web框架-MVC初体验

jw的github地址是https://github.com/menyouping/jw

第一次看到这篇文章时非常惊讶,介绍FastPHP如何实现一个简易的MVC。我的大脑中总是将Servlet与Spring MVC割裂开来,总认为是两个事物,看到这篇文章后茅塞顿开!Java版的MVC,我也可以玩了!

理一下思路:当外界发送一个请求,被jw-web拦截,请求跳转到一个自定义的HttpServlet中,Servlet解析请求地址再将请求转到相应的Controller类中,Controller类的相应函数进行逻辑处理后返回响应内容,这样MVC逻辑就走完了,是不是感觉有点简单,用Java反射功能就能实现。

下面我们一步步去完成这个MVC。

添加依赖

修改jw-parent/pom.xml

在modules节点下面添加兄弟节点,统一管理整个项目依赖的外部资源版本信息

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>servlet-apiartifactId>
            <version>2.5version>
        dependency>
        <dependency>
            <groupId>org.slf4jgroupId>
            <artifactId>slf4j-log4j12artifactId>
            <version>1.7.2version>
        dependency>
        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>1.2.16version>
        dependency>
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>3.8.1version>
            <scope>testscope>
        dependency>
    dependencies>
dependencyManagement>

修改jw-core/pom.xml

添加依赖

<dependencies>
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>servlet-apiartifactId>
    dependency>
    <dependency>
        <groupId>org.slf4jgroupId>
        <artifactId>slf4j-log4j12artifactId>
    dependency>
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>fastjsonartifactId>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <scope>testscope>
    dependency>
dependencies>

修改jw-web/pom.xml

添加依赖

<dependency>
    <groupId>javax.servletgroupId>
    <artifactId>servlet-apiartifactId>
dependency>
<dependency>
    <groupId>org.slf4jgroupId>
    <artifactId>slf4j-log4j12artifactId>
dependency>
<dependency>
    <groupId>com.alibabagroupId>
    <artifactId>fastjsonartifactId>
dependency>

修改web.xml

修改jw-web/src/main/webapp/WEB-INF/web.xml,在其中注册servlet, 拦截jw-web应用下的所有请求

<servlet>
    <servlet-name>appServletservlet-name>
    <servlet-class>com.jw.web.servlet.DispatcherServletservlet-class>
    <load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
    <servlet-name>appServletservlet-name>
    <url-pattern>/url-pattern>
servlet-mapping>

创建Servlet

新建文件jw-core/src/main/java/com/jw/web/servlet/DispatcherServlet.java

package com.jw.web.servlet;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.jw.util.ConfigUtils;
import com.jw.util.StringUtils;

public class DispatcherServlet extends HttpServlet {
    private static final Logger LOGGER = LoggerFactory.getLogger(DispatcherServlet.class);

    private static final long serialVersionUID = -3874308705324703315L;

    public DispatcherServlet() {
    }

    public void init() {
    }

    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
        String appName = request.getSession().getServletContext().getContextPath();

        String path = request.getRequestURI().substring(appName.length());
        LOGGER.info("Request path is {}", path);
        // /index/index/ => /index/index
        if (path.length() > 1 && path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        } else if (path.startsWith("/")) {// /index/index => index/index
            path = path.replaceFirst("/", "");
        }
        if (path.isEmpty()) {
            path = "index/index";
        } else if (!path.contains("/")) {
            path += "/index";// index => index/index
        }
        String[] paths = path.split("/", 2);

        String controllerClazeName = ConfigUtils.getProperty("package.scan") + "." + StringUtils.upperFirst(paths[0])
                + "Controller";
        String methodName = paths[1];

        try {
            Class controllerClaze = Class.forName(controllerClazeName);
            Method method = controllerClaze.getMethod(methodName,
                    new Class[] { HttpServletRequest.class, HttpServletResponse.class });

            Object controller = controllerClaze.newInstance();
            Object result = method.invoke(controller, new Object[] { request, response });
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(result));
        } catch (Exception e) {
            LOGGER.error("Error raised in DispatcherServlet.", e);
            Map result = new HashMap();
            result.put("status", 500);
            result.put("message", e.getMessage());
            response.setHeader("Content-type", "application/json;charset=UTF-8");
            response.getWriter().write(JSON.toJSONString(result));
        }
    }
}

controllerClazeName由两部分组成,第一部分ConfigUtils.getProperty(“package.scan”)是package的路径,第二部分是Controller的类名StringUtils.upperFirst(paths[0]) + “Controller”, StringUtils.upperFirst()使首字母大写。

添加配置文件jw-web/src/main/resources/application.properties

package.scan=com.jay.mvc

package.scan配置了Controller类所在的package地址。

新增类jw-core/src/main/java/com/jw/util/StringUtils.java

package com.jw.util;

public class StringUtils {
    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }

    /**
     * 首字母大写
     * 
     * @param str
     * @return
     */
    public static String upperFirst(String str) {
        if (StringUtils.isEmpty(str))
            return str;

        char ch = str.charAt(0);
        if (ch < 'a' || ch > 'z')
            return str;

        char[] cs = str.toCharArray();
        cs[0] = Character.toUpperCase(ch);
        return String.valueOf(cs);
    }
}

测试

添加测试Controller

新增类jw-web/src/main/java/com/jay/mvc/IndexController.java

package com.jay.mvc;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IndexController {

    public Object index(HttpServletRequest request, HttpServletResponse response) {
        Map result = new HashMap();
        result.put("status", 200);
        result.put("message", "index method is invorked!");
        return result;
    }

    public Object welcome(HttpServletRequest request, HttpServletResponse response) {
        Map result = new HashMap();
        result.put("status", 200);
        result.put("message", "Welcome to jw's world!");
        return result;
    }
}

添加Tomcat7 server

这一步不介绍了

修改Project Facets

检查一下Project Facets设置,Dynamic Web Module必须是2.5。若当前设置是2.3,打开文件jw-web/.settings/org.eclipse.wst.common.project.facet.core.xml
,修改jst.web和java的jdk版本,可参考此文。


<faceted-project>
  <fixed facet="wst.jsdt.web"/>
  <installed facet="jst.web" version="2.5"/>
  <installed facet="wst.jsdt.web" version="1.0"/>
  <installed facet="java" version="1.7"/>
faceted-project>

消除错误

如果在Problem面板中看到xx/target/classes/META-INF/MANIFES no such file or directory的错误,依次点击菜单Window/Preference/Maven/Java EE Intergration, 不勾选Maven Archiver generates files under the build directory。

启动jw-web

选中jw-web,右键Debug As -> Debug on Server
服务器启动,打开了http://localhost:8080/jw-web/ ,显示如下

Hello World!

显示内容来自于jw-web/src/main/webapp/index.jsp

测试jsp

修改网址,http://localhost:8080/jw-web/index.jsp,回车。
页面仍显示:

Hello World!

测试MVC

MVC的地址规则是http://localhost:8080/jw-web/{{controller}}//{{method}}
,{{method}}不填时默认为index方法。
修改网址,http://localhost:8080/jw-web/index ,回车。
调试时可以看到controllerClazeName的运行时值是”com.jay.mvc.IndexController”,成功找到目标Controller.
method的值是”com.jay.mvc.IndexController.index(HttpServletRequest,HttpServletResponse)”, 目标方法也找到。
最后看到页面显示:

{"message":"index method is invorked!","status":200}

修改网址,http://localhost:8080/jw-web/welcome,回车。
页面显示:

{"message":"com.jay.mvc.WelcomeController","status":500}

出错了,因为没有找到WelcomeController。

修改网址,http://localhost:8080/jw-web/index/welcome,回车。
页面显示:

{"message":"Welcome to jw's world!","status":200}

至此简单的MVC完成。

本节资源地址: https://github.com/menyouping/jw-example/blob/master/3/jw-parent.zip

你可能感兴趣的:(java)