Servlet MVC 项目实战实例
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
在这里,主要的操作步骤如下:
- 用户名,生日,会员状态填写后,点击增加信息,成功后,跳到显示所有用户界面(如果没有填写,有相应的后台验证信息),该界面有直接访问所有用户界面的链接,可以直接跳转查看所有用户信息。
- 在所有用户显示界面,将有修改,删除,增加用户三个操作,如果点击修改,则跳转到用户修改界面,当然当前修改的信息将直接在修改界面中显示,如果点击删除,将从数据库中删除这条信息,如果点击增加用户,则回到步骤一。
- 在用户修改界面,将有确认修改信息和显示所有信息两个操作,如果确认修改,将对数据库中修改的用户进行信息更新,如果显示所有信息,将执行步骤二。
这个过程中有着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 项目实战实例的更多相关文章
- ASP.NET Core 2.0 MVC项目实战
一.前言 毕业后入职现在的公司快有一个月了,公司主要的产品用的是C/S架构,再加上自己现在还在学习维护很老的delphi项目,还是有很多不情愿的.之前实习时主要是做.NET的B/S架构的项目,主要还是 ...
- PHP之MVC项目实战(三)
本文主要包括以下内容 标准错误错误处理 http操作 PDO 文件操作 标准错误错误处理 PHP在语法层面上发生的错误 两个过程: 触发阶段(发生一个错误) 处理阶段(如何处理该错误) 触发阶段 系统 ...
- PHP之MVC项目实战
本文主要包括以下内容 类文件自动加载 路径管理 页面跳转 注册自动加载方法 配置文件系统 cookie session 类文件自动加载 在PHP中使用别的类时,需要载入类文件,如果类很多的话,需要重复 ...
- PHP之MVC项目实战(二)
本文主要包括以下内容 GD库图片操作 利用GD库实现验证码 文件上传 缩略图 水印 GD库图片操作 <?php $img = imagecreatetruecolor(500, 300); // ...
- asp.net mvc项目实战遇见问题及解决方式----ajax请求500错误,请求多表数据
ajax请求出现500错误——但是想实现的功能是,把一个页面分成了两份,点击右边导航栏,利用ajax请求,请求数据,在右边出现相应页面,当时使用的是partialAction然后出现了这个500错误, ...
- Asp.Net Core 2.0 项目实战(9) 日志记录,基于Nlog或Microsoft.Extensions.Logging的实现及调用实例
本文目录 1. Net下日志记录 2. NLog的使用 2.1 添加nuget引用NLog.Web.AspNetCore 2.2 配置文件设置 2.3 依赖配置及调用 ...
- 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 ...
- 【WEB API项目实战干货系列】- API访问客户端(WebApiClient适用于MVC/WebForms/WinForm)(四)
这几天没更新主要是因为没有一款合适的后端框架来支持我们的Web API项目Demo, 所以耽误了几天, 目前最新的代码已经通过Sqlite + NHibernate + Autofac满足了我们基本的 ...
- Asp.Net Core 2.0 项目实战(6)Redis配置、封装帮助类RedisHelper及使用实例
本文目录 1. 摘要 2. Redis配置 3. RedisHelper 4.使用实例 5. 总结 1. 摘要 由于內存存取速度远高于磁盘读取的特性,为了程序效率提高性能,通常会把常用的不常变动的数 ...
随机推荐
- Java类型的生命周期
以上就是我今天没有总结学习类加载器时候对类加载器仅有的知识,虽然有个大概印象,但是还是有点模糊.今天一口气总结一下,参考文献我就不列举了.本文不生产知识,只是知识的搬运工. 静态.class文件到内存 ...
- (转)windows环境vue+webpack项目搭建
首先,vue.js是一种前端框架,一般利用vue创建项目是要搭配webpack项目构建工具的,而webpack在执行打包压缩的时候是依赖node.js的环境的,所以,要进行vue项目的开发,我们首先要 ...
- python 提示 AttributeError: module 'json' has no attribute 'dumps'
最近在学习python解析json的时候遇到问题, 提示 AttributeError: module 'json' has no attribute 'dumps' (模块没有dumps属性的意思) ...
- ftp的主动模式active mode和被动模式 passive mode的配置和区别
ftp的主动模式active mode和被动模式 passive mode的配置和区别 2017年05月08日 17:47:16 阅读数:21768 本文主要记录的是在linux上的区别,弄了一整天才 ...
- QSignalMapper类处理多信号关联同一个槽的方法(1)
QSignalMapper这个类并不是个新鲜概念, 早在Qt2里就已经存在, 而且它的功能也是始终如一. 不过由于宣传力度不够(例子里涉及到它的很少)了解这个类人可能还不是很多, 所以特此撰文介绍此类 ...
- 《FPGA全程进阶---实战演练》第三章之PCB设计之去耦电容
1.关于去耦电容为何需要就近摆放? 大多数资料有提到过,去耦电容就近放置,是从减小回路电感的角度去谈及摆放问题,其实还有一个原则就是去耦半径的问题,如果电容离着芯片位置较远,超过去耦半径,会起不到去耦 ...
- 类的数据成员加前缀 m_(表示 member)
类的数据成员加前缀 m_(表示 member),这样可以避免数据成员与 成员函数的参数同名. 例如: void Object::SetValue(int width, int height) { m_ ...
- java反射详解 (转至 http://www.cnblogs.com/rollenholt/archive/2011/09/02/2163758.html)
本篇文章依旧采用小例子来说明,因为我始终觉的,案例驱动是最好的,要不然只看理论的话,看了也不懂,不过建议大家在看完文章之后,在回过头去看看理论,会有更好的理解. 下面开始正文. [案例1]通过一个对象 ...
- Linux Vi/Vim 的使用及实例
什么是 vim? Vim是从 vi 发展出来的一个文本编辑器.代码补完.编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用. 简单的来说, vi 是老式的字处理器,不过功能已经很齐全了,但是 ...
- MVC生成图片验证码,可指定位数
前台: <h2>mvc后台生成验证码,可指定位数</h2> <img id="gc" src="GetValidateCode" ...