我们都知道MVC有两个经典的模式,MVC1和MVC2:
View接受用户输入,并传递到Controller。 Controller统一进行处理命令,交由Model处理具体的业务。 经过处理Model更新后,通知View进行更新。
这种模式主要用于桌面程序,使用观察者模式实现,具体来说就是让View观察Model,而用户交互控制的地方用匿名类的方式统一放在Controller中。像MFC的frame-document-view架构,如果document改变了,他会主动通知View进行update。但是在WEB应用程序中,Model(在Java中通常是JavaBean)的数据更新后,无法通知View进行更新(View在Java中通常是非常多JSP页面,需要选择一个),因此,在WEB应用程序中应该使用下面这种模式:MVC2模式
View接受用户输入,并传递到Controller。 Controller统一进行处理命令,交由model处理具体的业务。 经过处理的Model更新后,Controller会选一个View并把Model内容传递(request,session)给它(forward)。然后View进行显示。
两者区别: Model是否能主动通知View就是MVC1和MVC2模式的主要差别。桌面程序可以做到,所以使用MVC1;Web程序由于Http协议的限制做不到,所以使用MVC2
本例简单使用 JSP+Servlet+JavaBean 实现一个简单的MVC模式,因为MVC1模式适合桌面程序,web应用程序适合使用MVC2模式,所以我们要实现的是MVC2模式。
1.首先创建Maven的web工程,配置pom.xml依赖如下:
<dependencies>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20160810</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
2.WEB-INF目录下的web.xml文件配置内容如下,不然使用不了EL表达式:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
</web-app>
3.在resource目录下创建一个json文件,这个json文件是用于配置model层信息以及响应页面的,它相当于一个池子,配置信息内容如下:
{
"mvc":[
{
"actionName":"/login",
"className":"org.zero01.javabean.LoginBean",
"ok":"success.jsp",
"error":"index.jsp"
}
]
}
4.编写主页面index.jsp,做一个简单的表单提交模拟登录,内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Title</title>
</head>
<body>
<p style="color: red">${error}</p>
<form action="login.action" method="post">
<input type="text" name="username" placeholder="用户名"/><br>
<input type="password" name="password" placeholder="密码"/><br>
<input type="submit"/>
</form>
</body>
</html>
5.编写success.jsp,该页面是登录成功后响应的页面,内容如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<script>
alert("登录成功!");
</script>
<body>
</body>
</html>
6.完成以上view层的编写后,先编写model层。声明一个抽象接口,简单应用面向接口编程,Login.java内容如下:
package org.zero01.javabean;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Login {
public String excute(HttpServletRequest req, HttpServletResponse resp);
}
7.实现以上声明的接口,LoginBean.java内容如下:
package org.zero01.javabean;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginBean implements Login {
public String excute(HttpServletRequest req, HttpServletResponse resp) {
// 接收表单数据
String userName = req.getParameter("username");
String password = req.getParameter("password");
// 验证表单数据,返回相应的结果
if (userName == null || userName.trim().equals("") || password == null || password.trim().equals("")) {
req.setAttribute("error","用户名或密码不能为空!");
return "error";
} else if (userName.equals("lisi") && password.equals("123456")) {
return "ok";
}
req.setAttribute("error","用户名或密码错误!");
return "error";
}
}
8.最后是完成Controller控制器的编写,ActionServlet.java内容如下:
package org.zero01.servlet;
import org.json.JSONArray;
import org.json.JSONObject;
import org.zero01.javabean.Login;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
@WebServlet("*.action")
public class ActionServlet extends HttpServlet {
private JSONObject config = null;
// 初始化时加载配置信息
public void init() throws ServletException {
try {
// 读取json文件的内容
File file = new File(this.getServletContext().getRealPath("WEB-INF"), "classes/mvc2.json");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
StringBuffer stringBuffer = new StringBuffer();
String line = null;
// 将读取的内容追加到字符串里
while ((line = bufferedReader.readLine()) != null) {
stringBuffer.append(line);
}
bufferedReader.close();
// 把字符串内容转换成json对象
config = new JSONObject(stringBuffer.toString());
System.out.println("配置信息加载完成!");
} catch (Exception e) {
e.printStackTrace();
System.err.println("配置信息加载失败!");
}
}
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 如果请求资源的后缀不是.action就报404
String uri = req.getRequestURI();
if (!uri.endsWith(".action")) {
resp.sendError(404, "The Page Not Found!");
return;
}
// 截取出请求资源的前缀
String actionName = uri.substring(0, uri.indexOf("."));
System.out.println(actionName);
try {
// 取出mvc数组中的json对象
JSONArray jsonArray = config.getJSONArray("mvc");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject object = jsonArray.getJSONObject(i);
// 调用相应的model
if (object.getString("actionName").equals(actionName)) {
Login login = (Login) Class.forName(object.getString("className")).newInstance();
String name = login.excute(req, resp);
// 将结果返回view
req.getRequestDispatcher(object.getString(name)).forward(req, resp);
return;
}
}
resp.sendError(404, "The Page Not Found!");
} catch (Exception e) {
e.printStackTrace();
resp.sendError(500, "The config file error!");
}
}
}
运行结果: