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 ...
随机推荐
- 从入门到入土:Lambda完整学习指南,包教包会!
什么是Lambda表达式 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口.lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使 ...
- 基于vue的cropper插件编写分享
目录 简介 实现功能 实现原理 github地址:https://github.com/yinzhida/vue-crop git clone: https://github.com/yinzhida ...
- 共享共建会让中国的5G加速吗?
9月9号,中国联通正式公告,已与中国电信签署<5G网络共建共享框架合作协议书>,将在全国范围内合作共建5G接入网络. 这则消息堪称爆炸性新闻,但却看不到什么深度分析,评论文章除了强调&qu ...
- 【跟唐老师学习云网络】 - 第6篇 ARP你在哪
[摘要] 这一章节你的角色就是ping报文这个"使者",你要去往目的地,然后回到本机.然而目的地路漫漫,不知道要经过多少个小地盘(局域网),没两把刷子也不好行走江湖.所以你作为使者 ...
- gitbook 入门教程之自定义不一样的多语言首页插件
自定义多语言主页 中文 | English
- [AHOI2017初中组]guide
题目描述 农场主John最近在网上买了一辆新车,在购买汽车配件时,John不小心点了两次"提交"按钮.导致汽车上安装了两套GPS系统,更糟糕的是John在使用GPS导航时,两套系统 ...
- luogu P4170 [CQOI2007]涂色
题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符串表示这个目标:RGBGR. 每次你可以把一段连续的木版涂成一个 ...
- HDU5973 Game of Geting Stone(威佐夫博弈)
Two people face two piles of stones and make a game. They take turns to take stones. As game rules, ...
- SPOJ Distanct Substrings(求不同子串的数量)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- Redis中的Java分布式缓存
为什么在分布式Java应用程序中使用缓存?今天学习了两节优锐课讲解分布式缓存的内容,收获颇多,分享给大家. 在提高应用程序的速度和性能时,每毫秒都是至关重要的.例如,根据Google的一项研究,如果网 ...