JAVA框架-MVC模式

MVC

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

  • Model(模型) - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
  • View(视图) - 视图代表模型包含的数据的可视化。
  • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

案例

下面我们来写一个简单的登录的案例,来提现MVC的设计模式

首先,我们有一个数据库,里面存放用户信息如下:

OK,下一步我们建立一个简单的登录界面前端的页面如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title> 登录界面 </title>
</head>
<body>
    <span style="color: #ff4a4f" >${requestScope.err}</span>
    <form action="UserLogin">
        用户名:<input name="username"/><br>
        密码:<input name="password"/><br>
        <input type="submit" value="登录"/>
    </form>

</body>
</html>

如果我们不使用MVC的设计的话,程序应该如下:

package Servelet;

import utils.JDBCutil;

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.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@WebServlet(name = "LoginServlet", urlPatterns = "/LoginServlet")
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println(username);
        System.out.println(password);
        System.out.println("测试");

        try {
            //1.数据库的连接
            String JDBCDRVIER="com.mysql.jdbc.Driver";
            String URL="jdbc:mysql://localhost:3306/ProjectServlet";
            String USER="root";
			String PASSWORD="3692512";
            Class.forName(JDBCDRVIER);
            Connection c = DriverManager.getConnection(URL,USER,PASSWORD)
            System.out.println("数据库连接成功,正在查询....");
            
            //2.数据的查询
            String sql = "select * from user where username=? and password=?";
            PreparedStatement p = c.prepareStatement(sql);
            p.setObject(1,username);
            p.setObject(2,password);
            ResultSet rs = p.executeQuery();
            
            //3.进行业务逻辑判断
            if(rs.next()) {
                request.getSession().setAttribute("username",username);
                request.getSession().setAttribute("password",password);
                System.out.println("用户查询成功!跳转主页中.....");
                //不能转发,要用重定向,防止用户多次回车访问
				//request.getRequestDispatcher("index.jsp");
                response.sendRedirect("index.jsp");
            }else{
                System.out.println("用户名或密码不正确,跳转登录页面中.....");
                request.setAttribute("err","用户名或密码不正确");
                request.getRequestDispatcher("login.jsp").forward(request,response);
            }


        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}

下面我们使用MVC设计模式,来重写上述案例。

Model

其实MVC中的M实际上就是根据数据库封装的Bean。这部分没什么好说的,我们利用Bean对象来存储我们的数据。

package Servelet.models;

//用于对应数据库中的信息
public class UserBean {
    String username;
    String password;
    String nickname;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    @Override
    public String toString() {
        return "UserBean{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", nickname='" + nickname + '\'' +
                '}';
    }
}

Controller

这部分是Servelet程序,页面访问首先触发controller,主要作用就是

package Servelet.controllers;

import Servelet.models.UserBean;
import Servelet.services.UserServices;
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;


@WebServlet(name = "UserControllerServlet" ,urlPatterns = "/UserLogin")
public class UserControllerServlet extends HttpServlet {
    private UserServices services;

    @Override
    public void init() throws ServletException {
        services = new UserServices();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        System.out.println(username);
        System.out.println(password);

        try {
            UserBean bean = services.checkLogin(username, password);
            if(bean!=null){
                System.out.println("用户查询成功!跳转主页中.....");
                request.getSession().setAttribute("username",bean);
//                request.getRequestDispatcher("index.jsp");
                response.sendRedirect("index.jsp");
            }else {
                request.setAttribute("err","用户名或密码不正确");
                request.getRequestDispatcher("login.jsp").forward(request,response);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

这个部分可以看到我们仅仅做了逻辑判断,和数据库交互的工作和业务逻辑我们交给services对象。

Services

package com.kkb.services;

import com.kkb.dao.UserDao;
import com.kkb.models.UserBean;

import java.sql.*;

//用于处理用户相关的业务逻辑
public class UserService {
    private UserDao dao;

    public UserService() {
        dao = new UserDao();
    }
    //处理的登录逻辑  没有使用DAO之前
    public UserBean checkLogin(String username,String pwd) throws Exception{
        
        //连接数据库
        String JDBCDRVIER="com.mysql.jdbc.Driver";
        String URL="jdbc:mysql://localhost:3306/ProjectServlet";
        String USER="root";
        String PASSWORD="3692512";
        Class.forName(JDBCDRVIER);
        Connection connection = DriverManager.getConnection(URL,USER,PASSWORD)
        System.out.println("数据库连接成功,正在查询....");
		
        //查询数据库
        PreparedStatement statement = connection.prepareStatement("select *from user where username = ? and password = ?");
        statement.setObject(1,username);
        statement.setObject(2,password);
        ResultSet resultSet = statement.executeQuery();
        if (resultSet.next()){
            //将数据打包成一个UserBean
            UserBean bean = new UserBean();
            //从结果集中取出数据
            bean.setId(resultSet.getInt(1));
            bean.setName(resultSet.getString(2));
            bean.setPwd(resultSet.getString(3));
            //返回bean  表示登录成功了
            return bean;
        }else{
            //表示用户名和密码不正确
            return null;
        }
    }

但是,这里我们发现service里面既有业务逻辑的处理,也有和数据库的交互,这样代码的耦合程度高,不方便日后维护,所以我们考虑在原MVC的基础上添加DAO层,专门用来和数据库交互,这样能够进一步降低代码的耦合度。

DAO

这里的DAO就是我们专门和数据库打交道的地方,引入DAO后的逻辑可用下图表示。

这里我们dao层有两个java文件,一个是DBTool,是封装的数据库工具类,一个是UserDao,输入username返回bean对象(注意,这里仅仅是输入username,不执行是否密码一致的逻辑业务判断,判断是上一层service的范畴)

package dao;

import models.UserBean;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class UserDAO {

    private DBTool dbTool;

    public UserDAO()  {
        try {
            this.dbTool = new DBTool();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    // 根据用户名获取一条数据
    public UserBean selectUserByName(String username){
        //编写sql
        String sql = "select *from user where username = ?";
        //调用连接类来执行sql
        try {
            List<Map<String, Object>> maps = dbTool.executeQuery(sql, username);
            if (maps.size() > 0){
                return mapToUserBaen(maps.get(0));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //将map 转换为对象
    public UserBean mapToUserBaen(Map<String,Object> map){
        //把map转为UserBean
        UserBean bean = new UserBean();
        bean.setUsername((String) map.get("username"));
        bean.setPassword((String) map.get("password"));
        bean.setNickname((String) map.get("nickname"));
        return bean;
    }

    public void insertUser(String name, String pwd) throws SQLException {
        String sql = "insert into user values(null,?,?)";
        dbTool.executeUpdate(sql,name,pwd);
    }
}

package dao;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DBTool {

    public   String ip = "127.0.0.1";
    public   int port = 3306;
    public   String
            user="root",
            password="3692512",
            charset ="utf8",
            dbName="ProjectServlet";
    private static boolean DriverLoaded=false;

    //使用默认参数链接数据库
    public DBTool() throws ClassNotFoundException {
        if(DriverLoaded)return;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            System.out.println("DBTools message:数据库驱动加载成功!");
        } catch (ClassNotFoundException e) {
            System.out.println("DBTools Error:驱动程序加载失败!");
            throw e;
        }
        DriverLoaded=true;
    }

    //自定义参数初始化
    public DBTool(String ip, int port, String user, String password, String dbName) throws ClassNotFoundException {
        this();
        this.ip = ip;
        this.port = port;
        this.user = user;
        this.password = password;
        this.dbName = dbName;
    }

    //自定义参数初始化
    public DBTool(String user, String password, String dbName) throws ClassNotFoundException {
        this();
        this.user = user;
        this.password = password;
        this.dbName = dbName;
    }

    //获取一个链接
    public Connection getConnection() throws SQLException {
        String url = String.format("jdbc:mysql://%s:%s/%s?characterEncoding=%s&user=%s&password=%s&useSSL=false",ip,port,dbName,charset,user,password);
        try {
            return DriverManager.getConnection(url);
        } catch (SQLException e) {
            System.out.println("DBTools Error 数据库连接失败!");
            throw e;
        }
    }

    //执行查询语句
    public List<Map<String,Object>> executeQuery(String sql, Object...args) throws SQLException {
        ArrayList<Map<String, Object>> res = new ArrayList<>();

        ResultSet resultSet = null;
        PreparedStatement preparedStatement = null;
        Connection connection = null;
        try {
            connection = getConnection();
            preparedStatement = getPreparedStatement(connection, sql, args);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                resultSet.getMetaData().getColumnCount();
                HashMap<String, Object> map = new HashMap<>();
                for (int i = 1; i <= resultSet.getMetaData().getColumnCount() ; i++) {
                    map.put(resultSet.getMetaData().getColumnName(i),resultSet.getObject(i));
                }
                res.add(map);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if(resultSet != null)
                resultSet.close();
            if(preparedStatement != null)
                preparedStatement.close();
            if(connection != null)
                connection.close();
        }
        return res;
    }

    //sql参数预处理
    private PreparedStatement getPreparedStatement(Connection connection, String sql, Object[] args) throws SQLException {
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        int count = sql.length() - sql.replace("?", "").length();
        if(count != args.length){
            throw new SQLException("DBTool Error: 参数个数不匹配");
        }
        for (int i = 0; i < args.length; i++) {
            preparedStatement.setObject(i+1,args[i]);
        }
        return preparedStatement;
    }

    //执行更新语句   包括delete update insert
    public boolean executeUpdate(String sql,Object...args) throws SQLException {

        try {
            Connection connection = getConnection();
            PreparedStatement preparedStatement = getPreparedStatement(connection, sql, args);
            int i = preparedStatement.executeUpdate();
            if (i>0){return true;}
        } catch (SQLException e) {
            e.printStackTrace();
            throw e;
        }
        return false;
    }
}

最后当我们写好dao层后,我们修改service如下:

package services;

import dao.DBTool;
import dao.UserDAO;
import models.UserBean;

import java.sql.*;

public class UserServices {
    private UserDAO dao;

    public UserServices() {
        dao = new UserDAO();
    }

    public UserBean checkLogin(String username, String password) throws Exception{

        UserBean userBean = dao.selectUserByName(username);
        if(userBean != null){
            if(userBean.getPassword().equals(password)){
                return userBean;
            }
        }
        return null;

//        //连接数据库
//        String JDBCDRVIER="com.mysql.jdbc.Driver";
//        String URL="jdbc:mysql://localhost:3306/ProjectServlet";
//        String USER="root";
//        String PASSWORD="3692512";
//        Class.forName(JDBCDRVIER);
//        Connection connection = DriverManager.getConnection(URL,USER,PASSWORD);
//        System.out.println("数据库连接成功,正在查询....");
//
//        //查询数据库
//        PreparedStatement statement = connection.prepareStatement("select *from user where username = ? and password = ?");
//        statement.setObject(1,username);
//        statement.setObject(2,password);
//        ResultSet resultSet = statement.executeQuery();
//        if (resultSet.next()){
//            //将数据打包成一个UserBean
//            UserBean bean = new UserBean();
//            //从结果集中取出数据
//            bean.setUsername(resultSet.getString(1));
//            bean.setPassword(resultSet.getString(2));
//            bean.setNickname(resultSet.getString(3));
//            //返回bean  表示登录成功了
//            return bean;
//        }else{
//            //表示用户名和密码不正确
//            return null;
//        }



    }
}

可以看到,我们通过MVC+Dao的形式,实现了程序的解耦,这样修改需求的时候,我们可以方便后序的维护。

posted @ 2020-07-03 20:57  不愿透漏姓名的王建森  阅读(415)  评论(0编辑  收藏  举报