MVC
MVC 模式代表 Model-View-Controller(模型-視圖-控制器) 模式。這種模式用于應用程序的分層開發。
Model(模型) - 模型代表一個存取數據的對象或 JAVA POJO。它也可以帶有邏輯,在數據變化時更新控制器。
View(視圖) - 視圖代表模型包含的數據的可視化。
Controller(控制器) - 控制器作用于模型和視圖上。它控制數據流向模型對象,并在數據變化時更新視圖。它使視圖與模型分離開。
案例
下面我們來寫一個簡單的登錄的案例,來提現MVC的設計模式
首先,我們有一個數據庫,里面存放用戶信息如下:
OK,下一步我們建立一個簡單的登錄界面前端的頁面如下:
登錄界面${requestScope.err}
用戶名:
密碼:
如果我們不使用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> 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 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> executeQuery(String sql, Object...args) throws SQLException {
ArrayList> 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 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的形式,實現了程序的解耦,這樣修改需求的時候,我們可以方便后序的維護。