欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaWeb中的MVC

程序员文章站 2023-10-29 08:22:10
不使用什么MVC的案例分析: 利用Servlet与jsp实现登陆请求,数据库查询,以及页面的跳转逻辑 具体流程如下: 不做任何结构上的考虑,可以简单的做如下实现: 目录结构 LoginServlet login.jsp index.jsp 增加需求 通过简单的逻辑判断和JDBC就实现了上述需求,接下 ......

不使用什么mvc的案例分析:

利用servlet与jsp实现登陆请求,数据库查询,以及页面的跳转逻辑

具体流程如下:

JavaWeb中的MVC

不做任何结构上的考虑,可以简单的做如下实现:

目录结构

JavaWeb中的MVC

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就实现了上述需求,接下来我们继续增加需求

假设现在要增加注册功能,可以这样:

  1. 创建register.jsp
  2. 创建 registerservlet
  3. 在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为了满足可重用性,有更多的规范要求

图示:

JavaWeb中的MVC

注意:

view与model层之间不允许直接交互,必须由controller来调度

service层

按照这样的层次结构,将servlet用于controller层,在增加一个bean类,来装载数据,看起来不错,但是没有解决根本的问题,业务逻辑和数据库操作依然挤在servlet中,必须在对其进行拆分,于是在mvc基础结构上增加service层,用于处理业务逻辑,你也可以叫它业务逻辑层(business)

看起来就像下面这样:

JavaWeb中的MVC

你可能会问,service属于m还是c,它既不是c也不是m,是我们在mvc基础上扩展出来的,我们经常会在已有模式上扩展新的内容这很正常

使用mvc

现在对之前的程序进行改造

  • 增加javabean,其中的属性与对应的表相同,拥有id,name,password
  • 增加service包,并创建userservice类,用作业务逻辑层
  • 在控制器servlet中,调用service来完成业务功能
  • 根据service的返回结果来决定页面的跳转地址
项目结构:

JavaWeb中的MVC

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;