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中常见模式>>
一书中讲到的;
针对web项目,mvc就是非常通用的设计模式,那如何去设计一款mvc的程序呢?
mvc分层
为了降低各个功能间的耦合度,提高代码的可维护性,mvc将程序分为了三个层次
m:model 模型,用于作为数据的载体的bean,通常不包含复杂逻辑,一个bean对应数据库一条记录
v:view 视图,用于展示model中的数据,处理用户交互,从而更新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依然只能处理用户的登录请求
follow me,seeyou next blog;