MVC的架构模式,一直是JavaEE开发中所遵循的标准,如今很多框架都已经很好的实现了MVC,像大家所熟知的Struts,SpringMVC,JSF等,但是如果没有任何框架的支持,仅仅通过JavaWeb中servlet,jsp等基本知识的运用,可以如何实现MVC的开发模式呢?本文将通过一个实例来讲解Servlet所实现的MVC架构。

下载项目源码请点击这里:

http://download.csdn.net/download/songdeitao/6802255

由于本项目在实现的过程中有很多建立的细节,这些都在我之前的博文中有所提及,而在此文中就直接默认所有的问题都已经解决,然后运用了JDBC轻量型封装的DAO框架,对于Servlet中文乱码的解决采取了过滤器的处理,对于Mysql可能遇到的中文乱码问题都已经解决,如果有此方面的疑惑或者问题的话,可以参考一下三篇博文:

资源引入

http://blog.csdn.net/songdeitao/article/details/17711015

http://blog.csdn.net/songdeitao/article/details/17577823

http://blog.csdn.net/songdeitao/article/details/17484635

下面就来构建整个ServletMVC的实战项目

项目概况

首先给出JavaWeb项目ServletMVC最终的结构,如图1所示:

图1

注:在这个过程中我将主要讲解基于Servlet的MVC架构的搭建过程,对于Dao的封装,mysql的sql语句,实体类的编写等我都不会提及,还请大家参照以上三个链接进行参照,最终的代码大家也可以在我分享的资源中进行下载,在这里我仅仅给出项目中相对重要的代码已经实现原理,有什么问题,我将会和大家共同解决。

下面给出在发布到Tomcat中后,通过http://localhost:8080/ServletMVC访问后可以实现的效果,如图2所示:

图2

在这里,主要的操作步骤如下:

  1. 用户名,生日,会员状态填写后,点击增加信息,成功后,跳到显示所有用户界面(如果没有填写,有相应的后台验证信息),该界面有直接访问所有用户界面的链接,可以直接跳转查看所有用户信息。
  2. 在所有用户显示界面,将有修改,删除,增加用户三个操作,如果点击修改,则跳转到用户修改界面,当然当前修改的信息将直接在修改界面中显示,如果点击删除,将从数据库中删除这条信息,如果点击增加用户,则回到步骤一。
  3. 在用户修改界面,将有确认修改信息和显示所有信息两个操作,如果确认修改,将对数据库中修改的用户进行信息更新,如果显示所有信息,将执行步骤二。

这个过程中有着action的标识的都是通过基于Servlet所实现的Controller来进行管理,也是MVC中的核心部分,下面将来讲解Servlet实现的MVC的具体原理和实现的步骤。

Servlet MVC实现

一般情况的MVC实现,都是通过多个继承HttpServlet的类充当Controller,因此需要多个Servlet的编写,在此文中,Controller只有一个类,而通过不同的Action类来执行相应的处理操作,因此在这个过程中,具体的实现原理图如图3所示:

图3

在这个过程中,主要的实现原理如下讲解:

比如图2中userAddAction这个过程,

ActionServlet是一个固定的处理方式的Controller,在方法中首先获取前端将要调用的action名字来确定指向,如userAddAction,前端就要通过userAdd.do?actionName=userAddAction的方式指向调用UserAddAction这个action类,而在ActionServlet中doPost(……)方法中,将获取actionName,即为userAddAction,而Servlet的生命周期中,init()方法是在doPost(……)方法之前执行的,而且只执行一次,这个时候因为已经将actionName对应userAddAction的实例new UserAddAction()添加到了application属性范围及web容器中(只有一个实例),所以就可以通过key->value的形式,获取要调用的action处理类UserAddAction,从而获取一个url,然后根据这个url跳转到相应的显示页面(show.jsp)。

下面给出这个过程中用到的资源文件:

ActionServlet.java(Controller)

package com.steven.controller;

import java.io.IOException;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.steven.model.UserAddAction;
import com.steven.model.UserDeleteAction;
import com.steven.model.UserListAction;
import com.steven.model.UserModifyAction;
import com.steven.model.UserUpdateAction;
import com.steven.util.IModel; /**
* 核心处理器类,用来接收客户端的所有请求, 根据请求调用模型实现业务逻辑的处理, 在模型处理完后根据处理结果再进行视图的转发
*
* @author Steven
*
*/
public class ActionServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取请求提交的参数,该参数用来标识执行的请求处理
String cmd = req.getParameter("actionName");
// 根据参数获取模型的实例
IModel model = (IModel) getServletContext().getAttribute(cmd);
// 通过模型对象进行业务逻辑处理,返回视图路径
String url = model.execute(req, resp);
// 根据视图路径进行页面转发
if (url != null) {
req.getRequestDispatcher(url).forward(req, resp);
} else {
// 如果路径出错,跳转到错误页面
req.getRequestDispatcher("WEB-INF/jsp/error.jsp")
.forward(req, resp);
}
} @Override
public void init() throws ServletException {
// 获取application
ServletContext application = getServletContext();
// 将业务模型的实例写入application
application.setAttribute("userAddAction", new UserAddAction());
application.setAttribute("userListAction", new UserListAction());
application.setAttribute("userModifyAction", new UserModifyAction());
application.setAttribute("userDeleteAction", new UserDeleteAction());
application.setAttribute("userUpdateAction", new UserUpdateAction());
} }

IModel(Model模型的接口)

IModel.java

package com.steven.util;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 模型接口,所有业务逻辑处理器都应实现该接口
*
* @author Steven
*
*/
public interface IModel {
/**
* 模型接口
*
* @param request
* @return
*/
public String execute(HttpServletRequest request,HttpServletResponse resp);
}

实现的Model处理器(UserAddAction)

UserAddAction.java

package com.steven.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.steven.dao.impl.UserDao;
import com.steven.entity.User;
import com.steven.util.IModel; /**
* 实现统一规定的模型
*
* @author Steven
*
*/
public class UserAddAction implements IModel {
// 获得数据库操作的DAO
private UserDao userDao;
// 获取日期操作类
private Calendar calendar = Calendar.getInstance(); public UserAddAction() {
userDao = new UserDao();
} @Override
public String execute(HttpServletRequest request,
HttpServletResponse response) {
// 获取前台表单提交后的用户名
String userName = request.getParameter("userName");
// 生日
String birthday = request.getParameter("birthday");
// 是否是VIP
String isVip = request.getParameter("isVip"); // 进行转换VIP的boolean类型
boolean isVipFlag = isVip.toLowerCase().equals("yes") ? true : false;
// 年龄
int age = 0; // 创建进行验证的标志信息
boolean checkFlag = true;
if ("".equals(userName) || userName == null) {
request.setAttribute("userNameError", "请填写用户名");
checkFlag = false;
} else {
request.setAttribute("userName", userName);
}
if (birthday != null && !"".equals(birthday)) {
// 得到年龄
age = calendar.get(Calendar.YEAR)
- Integer.parseInt(birthday.substring(0, 4)) + 1;
request.setAttribute("birthday", birthday);
} else {
checkFlag = false;
// 进行后台校验
request.setAttribute("birthdayError", "请选择出生日期"); }
// 如果有没有填的选项,则后台校验不成功,进行跳转
if (!checkFlag) {
return "index.jsp";
} // 穿件要创建的用户
User user = null;
try {
// 生成用户信息
user = new User(userName, age, new SimpleDateFormat("yyyy-MM-dd")
.parse(birthday), isVipFlag);
} catch (ParseException e) {
e.printStackTrace();
}
// 将用户添加到数据库中
userDao.doCreate(user);
// 获取用户集合,进行显示
List<User> userList = userDao.findAll(); // 设置到request属性范围中
request.setAttribute("userList", userList); // 设置跳转后的页面
return "WEB-INF/jsp/show.jsp";
} }

以及跳转后的视图show.jsp页面

show.jsp(View)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>User Show</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
--> </head> <body>
<c:if test="${not empty userList}">
<table style="width: 600px; text-align: center;" cellpadding="0"
cellspacing="0" border="1">
<tr>
<th>
用户名
</th>
<th>
年龄
</th>
<th>
生日
</th>
<th>
是否是会员
</th>
<th>操作</th>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>
${user.userName }
</td>
<td>
${user.age }
</td>
<td>
<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd" />
</td>
<td>
<c:choose>
<c:when test="${user.isVip}">是</c:when>
<c:otherwise>不是</c:otherwise>
</c:choose>
</td>
<td>
<a href="modify.do?actionName=userModifyAction&userId=${user.userId}">修改</a>
<a href="delete.do?actionName=userDeleteAction&userId=${user.userId}">删除</a>
</td>
</tr>
</c:forEach>
</table>
<br/>
  <a href="index.jsp">增加用户</a>
</c:if>
<c:if test="${empty userList}">
<h2>暂时还没有任何数据,点击<a href="index.jsp">此处</a>进行增添数据</h2>
</c:if>
</body>
</html>

因此这就是这个增加用户的功能所要实现的MVC封装架构,当然,对于ActionServlet需要配置web.xml

web.xml

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"> <title>User Show</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
--> </head> <body>
<c:if test="${not empty userList}">
<table style="width: 600px; text-align: center;" cellpadding="0"
cellspacing="0" border="1">
<tr>
<th>
用户名
</th>
<th>
年龄
</th>
<th>
生日
</th>
<th>
是否是会员
</th>
<th>操作</th>
</tr>
<c:forEach items="${userList}" var="user">
<tr>
<td>
${user.userName }
</td>
<td>
${user.age }
</td>
<td>
<fmt:formatDate value="${user.birthday}" pattern="yyyy-MM-dd" />
</td>
<td>
<c:choose>
<c:when test="${user.isVip}">是</c:when>
<c:otherwise>不是</c:otherwise>
</c:choose>
</td>
<td>
<a href="modify.do?actionName=userModifyAction&userId=${user.userId}">修改</a>
<a href="delete.do?actionName=userDeleteAction&userId=${user.userId}">删除</a>
</td>
</tr>
</c:forEach>
</table>
<br/>
  <a href="index.jsp">增加用户</a>
</c:if>
<c:if test="${empty userList}">
<h2>暂时还没有任何数据,点击<a href="index.jsp">此处</a>进行增添数据</h2>
</c:if>
</body>
</html>

这就是Servlet MVC实现的核心,其他的功能比如显示所有用户,删除用户,修改用户,所对应的action分别编写,Controller只有ActionServlet这个类,而init()方法中要将需要的actionName增加进去。

从这里很容易看出MVC的主要优缺点

优点:

  • Controller将Model和View分离,降低耦合度
  • ActionServlet类的重用,以及IModel的统一
  • 维护性高,以后添加相应的功能,只要照着这个模式编写即可,容易理解和编写

缺点:

  • 这个过程都是根据具体项目实施采取的封装模式,除非使用一些现成的框架,固定住了这个模式,否则没有明确定义
  • 开发前需要准备工作,对于一些轻型开发略显繁琐,复杂性高了,效率低了
  • 所有的控制都有Controller来控制,将显得View和Controller紧密联系,重用性较低

这就是整个Servlet MVC实现的核心,具体的代码还请参照代码资源

http://download.csdn.net/download/songdeitao/6802255

在此恭祝大家新年快乐,学习愉快!

Servlet MVC 项目实战实例的更多相关文章

  1. ASP.NET Core 2.0 MVC项目实战

    一.前言 毕业后入职现在的公司快有一个月了,公司主要的产品用的是C/S架构,再加上自己现在还在学习维护很老的delphi项目,还是有很多不情愿的.之前实习时主要是做.NET的B/S架构的项目,主要还是 ...

  2. PHP之MVC项目实战(三)

    本文主要包括以下内容 标准错误错误处理 http操作 PDO 文件操作 标准错误错误处理 PHP在语法层面上发生的错误 两个过程: 触发阶段(发生一个错误) 处理阶段(如何处理该错误) 触发阶段 系统 ...

  3. PHP之MVC项目实战

    本文主要包括以下内容 类文件自动加载 路径管理 页面跳转 注册自动加载方法 配置文件系统 cookie session 类文件自动加载 在PHP中使用别的类时,需要载入类文件,如果类很多的话,需要重复 ...

  4. PHP之MVC项目实战(二)

    本文主要包括以下内容 GD库图片操作 利用GD库实现验证码 文件上传 缩略图 水印 GD库图片操作 <?php $img = imagecreatetruecolor(500, 300); // ...

  5. asp.net mvc项目实战遇见问题及解决方式----ajax请求500错误,请求多表数据

    ajax请求出现500错误——但是想实现的功能是,把一个页面分成了两份,点击右边导航栏,利用ajax请求,请求数据,在右边出现相应页面,当时使用的是partialAction然后出现了这个500错误, ...

  6. Asp.Net Core 2.0 项目实战(9) 日志记录,基于Nlog或Microsoft.Extensions.Logging的实现及调用实例

    本文目录 1. Net下日志记录 2. NLog的使用     2.1 添加nuget引用NLog.Web.AspNetCore     2.2 配置文件设置     2.3 依赖配置及调用     ...

  7. Asp.Net Core 2.0 项目实战(4)ADO.NET操作数据库封装、 EF Core操作及实例

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  8. 【WEB API项目实战干货系列】- API访问客户端(WebApiClient适用于MVC/WebForms/WinForm)(四)

    这几天没更新主要是因为没有一款合适的后端框架来支持我们的Web API项目Demo, 所以耽误了几天, 目前最新的代码已经通过Sqlite + NHibernate + Autofac满足了我们基本的 ...

  9. Asp.Net Core 2.0 项目实战(6)Redis配置、封装帮助类RedisHelper及使用实例

    本文目录 1. 摘要 2. Redis配置 3. RedisHelper 4.使用实例 5. 总结 1.  摘要 由于內存存取速度远高于磁盘读取的特性,为了程序效率提高性能,通常会把常用的不常变动的数 ...

随机推荐

  1. 【C#学习笔记】反射的简单用法

    常见的使用反射的场景: 程序在运行时动态地访问类的成员,如获得类的变量.方法. 例如:用反射给本类的变量赋值. public class Student{ public string studentN ...

  2. 一站式学习Wireshark(九):应用Wireshark显示过滤器分析特定数据流(上)

    介绍 掌握显示过滤器对于网络分析者来说是一项必备的技能.这是一项大海捞针的技巧.学会构建,编辑,保存关键的显示过滤器能够节省数小时的时间. 与捕捉过滤器使用的BPF语法不同,显示过滤器使用的是Wire ...

  3. MongoDB(三):MongoDB概念解析

    在上一篇文章中讲解了如何安装MongoDB,这篇文章中讲解一些有关MongoDB的概念. 不管我们要学习什么数据库,都应该学习其中的基础概念,在MongoDB中基本的概念是文档.集合.数据库,下面挨个 ...

  4. HTTP API 设计指南(响应部分)

    前言 这篇指南介绍描述了 HTTP+JSON API 的一种设计模式,最初摘录整理自 Heroku 平台的 API 设计指引 Heroku 平台 API 指引. 这篇指南除了详细介绍现有的 API 外 ...

  5. ERROR 1290

    Mysql创建用户时.出现如下错误! mysql> create user 'testuse'@'localhost' identified by '111111'; ERROR 1290 (H ...

  6. springmvc拦截器的配置、使用

    springmvc拦截器的配置.使用:1.自定义拦截器,实现HandlerInterceptor接口. package com.bybo.aca.web.interceptor; import jav ...

  7. C语言中带参数的宏

    带参数的宏定义有如下的格式: [#define 指令----带参数的宏] #define 标识符(x1,x2,……,xn) 其中  x1,x2,……xn是标志符(宏的参数) 注意:在宏的名字和括号之间 ...

  8. glob 遍历函数

    例子 1 <?php print_r(glob("*.txt")); ?> 输出类似: Array ( [0] => target.txt [1] => s ...

  9. 关于PHP的特点

    魔术方法 当一个对象引用变量调用一个没有定义的属性或方法时,可以这一个函数.当发生这种情况时调用这种函数.

  10. 象“[]”、“.”、“->”这类操作符前后不加空格

    象“[]”.“.”.“->”这类操作符前后不加空格. #include <iostream> #include <process.h> #include<stdio ...