JavaWeb中的MVC
不使用什么MVC的案例分析:
利用Servlet与jsp实现登陆请求,数据库查询,以及页面的跳转逻辑
具体流程如下:
不做任何结构上的考虑,可以简单的做如下实现:
目录结构
LoginServlet
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.IOException;
import java.sql.*;
@WebServlet("/Login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req,resp);//转发到get 执行相同逻辑
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取参数
String name = req.getParameter("username");
String password = req.getParameter("pwd");
String error = null; //错误信息
boolean flag = false; //是否登陆成功
//验证数据可靠性
if(name == null || password == null || name.equals("") || password.equals("")){
error="用户名和密码不能为空!";
}else {
//查询数据库
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection("jdbc:mysql://127.0.0.1/db1?charsetEncoding=utf-8&user=root&password=admin");
PreparedStatement statement = connect.prepareStatement("select *from user where name = ? and password = ?");
statement.setObject(1,name);
statement.setObject(2,password);
ResultSet set = statement.executeQuery();
if(set.next()){
flag = true;
}else{
error="用户名和密码错误!";
}
} catch (ClassNotFoundException | SQLException e1) {
error = "服务器忙,请稍后再试!";
}
}
if(flag){
//删除已存在的错误信息,避免后续登录页面展示重复展示
req.getSession().removeAttribute("error");
//添加用户名称到session
req.getSession().setAttribute("user",name);
//跳转页面
req.getRequestDispatcher("./index.jsp").forward(req,resp);
}else{
//添加错误信息到session
req.getSession().setAttribute("error",error);
//跳转页面
req.getRequestDispatcher("./login.jsp").forward(req,resp);
}
}
}
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<span style="color: red">${error}</span>
<form action="./Login" method="post">
用户名:<input name="username"/>
<br>
密码:<input name="pwd">
<br>
<input type="submit" value="登录">
</form>
</body>
</html>
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>主页</title>
</head>
<body>
<h1>你好${user},欢迎登录</h1>
</body>
</html>
增加需求
通过简单的逻辑判断和JDBC就实现了上述需求,接下来我们继续增加需求
假设现在要增加注册功能,可以这样:
- 创建register.jsp
- 创建 RegisterServlet
- 在RegisterServlet,获取参数,链接数据库,处理注册逻辑
思考,这样写有什么问题?
- 按照这样的思路,一个功能就需要一个Servlet,而Servlet的生命周期是非常长的,将会大量消耗内存
- 如果不创建其他Servlet,那只能将所有URL交个同一个Servlet处理,这样的话就不可避免的需要对请求路劲进行判断,以确定客户端要执行的功能
- 每个功能都要重复的进行数据库的相关操作,例如连接数据库,提取结果等,出现了大量重复代码
上述列出的问题,在程序开发中是经常遇到的,所以我们不得不对程序的整体结构进行重新思考和设计
MVC
MVC是一种软件构架模式,所谓模式,就是前辈们给我们总结出的针对固定类型问题的已有解决方案
,这写方案是经过大量时间,以及大量项目实践,最终总结出的良好的方案;给开发者,提供了非常好的指导思想,在漫长的技术发展过程中,开发者们总结出了,很多好的模式,如<<23中常见模式>>
一书中讲到;
注意:严格来说MVC不属于设计模式,而是构架模式,因为MVC是为程序划分层了次结构,使得程序结构更规范,更合理,降低了耦合度
针对web项目,MVC就是非常通用的构架模式,到底如何去设计一款MVC的程序呢?
MVC分层
为了降低各个功能间的耦合度,提高代码的可维护性,MVC将程序分为了三个层次
M:Model 模型,用于作为数据的载体的Bean,通常不包含复杂逻辑,一个Bean对应数据库一条记录
V:View 视图,用于展示Model中的数据,和处理用户交互
C :Controller 控制器,接受View的输入,根据需要调用Mode,获取数据后再交给View层进行展示
补充POJO和Bean的区别,POJO更加简单只要求由set/get,而Bean为了满足可重用性,有更多的规范要求
图示:
注意:
View与Model层之间不允许直接交互,必须由Controller来调度
Service层
按照这样的层次结构,将servlet用于Controller,在增加一个Bean类,来装载数据,看起来不错,但是没有解决根本的问题,业务逻辑和数据库操作依然挤在Servlet中,必须在对其进行拆分,于是在MVC基础结构上增加Service
层,用于处理业务逻辑,你也可以叫它业务逻辑层(business)
看起来就像下面这样:
你可能会问,Service属于M还是C,它既不是C也不是M,是我们在MVC基础上扩展出来的,我们经常会在已有模式上扩展新的内容这很正常
使用MVC
现在对之前的程序进行改造
- 增加JavaBean,其中的属性与对应的表相同,拥有ID,name,password
- 增加service包,并创建UserService类,用作业务逻辑层
- 在控制器Servlet中,调用Service来完成业务功能
- 根据Service的返回结果来决定页面的跳转地址
项目结构:
UserLoginServlet:
package com.xx.controller;
import com.xx.exceptions.LoginException;
import com.xx.models.UserBean;
import com.xx.services.UserService;
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.IOException;
import java.sql.SQLException;
@WebServlet("/Login")
public class UserLoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取参数
String name = request.getParameter("username");
String pwd = request.getParameter("pwd");
UserBean reqBean = new UserBean(name,pwd);
//实例化业务逻辑对象
UserService service = new UserService();
try {
//调用对应方法 根据结构跳转页面
UserBean resBean = service.CheckLogin(reqBean);
request.getSession().setAttribute("user",resBean.getName());
response.sendRedirect(request.getServletContext().getContextPath() +"/index.jsp");
} catch (LoginException e) {
request.getSession().setAttribute("error",e.getMessage());
response.sendRedirect(request.getServletContext().getContextPath() +"/login.jsp");
}
}
}
UserService:
package com.xx.services;
import com.xx.exceptions.LoginException;
import com.xx.models.UserBean;
import java.sql.*;
public class UserService {
public UserBean CheckLogin(UserBean userBean) throws LoginException {
//验证参数有效性
if (userBean.getPassword() == null || userBean.getPassword() == null ||
userBean.getPassword().equals("") || userBean.getName().equals("")){
throw new LoginException("用户名和密码不能为空");
}
UserBean bean = null;
//查询数据库
try {
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/db1?characterEncoding=utf8&user=root&password=admin");
PreparedStatement preparedStatement = connection.prepareStatement("select *from user where name = ? and password = ?");
preparedStatement.setObject(1, userBean.getName());
preparedStatement.setObject(2, userBean.getPassword());
ResultSet set = preparedStatement.executeQuery();
if (set.next()) {
bean = new UserBean();
bean.setId(set.getInt(1));
bean.setName(set.getString(2));
bean.setPassword(set.getString(3));
}else {
throw new LoginException("用户名或密码错误!");
}
}catch (SQLException | ClassNotFoundException e){
e.printStackTrace();
throw new LoginException("服务器忙,(数据库炸了)",e);
}
return bean;
}
}
UserBean仅包含构造器,和setget方法
LoginException,也只是简单的继承了Exception
小结:
MVC是Web应用常用的设计模式,其增强了代码的扩展性,可维护性,降低了各组件的耦合度
在上述案例中通过MVC分层,代码结构得到了优化,但是细心的你可能已经发现了,
- 业务逻辑层Service中夹杂着与数据库相关的所有代码,导致代码冗余.重复代码问题依然没有得到解决
- UserLoginServlet依然只能处理用户的登录请求
JavaWeb中的MVC的更多相关文章
- JavaWeb中的MVC 下
代码较多,请先略过代码,看懂逻辑在研究代码 引入 回顾上一节中的项目,最终的层次结构: 在MVC上中,我们分析了MVC设计模式具备的优点,以及不足,并在其基础上增了Service层用于处理业务逻辑,但 ...
- MVC的设计模式在JavaWeb中的实现
JSP开发模式 jsp开发模式的发展 1.模式1:(适合小型项目的技术的开发) a.第一版本号,纯jsp(封装数据.处理数据,显示数据) b.第二版本号,Jsp+JavaBean. ...
- JavaWeb中监听器+过滤器+拦截器区别、配置和实际应用
JavaWeb中监听器+过滤器+拦截器区别.配置和实际应用 1.前沿上一篇文章提到在web.xml中各个元素的执行顺序是这样的,context-param-->listener-->fil ...
- javaWeb中的文件上传下载
在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现. 对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用 ...
- 转:攻击JavaWeb应用[5]-MVC安全
转:http://static.hx99.net/static/drops/tips-347.html 攻击JavaWeb应用[5]-MVC安全 园长 · 2013/07/25 13:31 注:这一节 ...
- 生活中的MVC模式,一个吃货的理解。
以下是生活中对于MVC模式的领悟,虽然可笑,轻喷. 2015年 8月 26日 M => Model 模型 我认为叫做模具更好的理解.批量加工生产具有相同特征的东西. ...
- 【干货理解】理解javascript中实现MVC的原理
理解javascript中的MVC MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程 ...
- 二十七、EFW框架BS系统开发中的MVC模式探讨
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...
- 在JavaWeb中使用Log4j步骤
在JavaWeb中使用Log4J指南.每次在开始写一个项目的时候都忘记Log4J如何配置.所以写个步骤,作为记录. 第一步 下载Log4J jar包 从Apache Logging Services ...
随机推荐
- 基于Docker搭建分布式消息队列Kafka
本文基于Docker搭建一套单节点的Kafka消息队列,Kafka依赖Zookeeper为其管理集群信息,虽然本例不涉及集群,但是该有的组件都还是会有,典型的kafka分布式架构如下图所示.本例搭建的 ...
- 【Python成长之路】从零学GUI -- 制作智能聊天机器人
[写在前面] 鹏哥:最近老惹小燕同学不开心,结果都没人陪我聊天了.哎,好无聊呀! 肥宅男:女朋友什么的最无聊了,还没我的图灵机器人好玩. 鹏哥:图灵?好巧,和我部门同名. [效果如下] [实现过程] ...
- 在modelarts上部署mask-rcnn模型
最近老山完成了对mask-rcnn在modelarts上的部署,部署模型来自于这个项目.部署的过程大体和我的上篇文章使用modelarts部署bert命名实体识别模型相似,许多细节也不在赘述.这篇文章 ...
- JQuery之选择集过滤
JQuery选择集过滤应用如下: 代码实现: <script src="JS/jquery-3.4.1.js"></script> <script&g ...
- replace find join
>>> s='spam' >>> s=s.replace('m','111') >>> s 'spa111' >>> where ...
- Cisco 7200 路由 PPPOE 拨号详解
1.1配置虚拟拨号接口 R1(config)#vpdn enable #启用vpdn虚拟专用拨号网络 R1(config)#interface dialer 1 ...
- Day 08 作业
有如下值集合 [11, 22, 33, 44, 55, 66, 77, 88, 99, 90...],将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中 ...
- 【Webpack】319- Webpack4 入门手册(共 18 章)(上)
介绍 1. 背景 最近和部门老大,一起在研究团队[EFT - 前端新手村]的建设,目的在于:帮助新人快速了解和融入公司团队,帮助零基础新人学习和入门前端开发并且达到公司业务开发水平. 本文也是属于[E ...
- 反射从入门到精通之深入了解Class类
.katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...
- CSS去除input和textarea点击选中框
1.去除chrome等浏览器默认发光边框 input:focus, textarea:focus { outline: none; } 这样textarea在选中的时候,文字会有点移动,解决方法: i ...