MVC模式一般由JSP+Servlet+JavaBean组成。其中JSP用于表示数据;Servlet用于处理客户请求,充当控制器的角色;JavaBean用于数据的存取。其运行机制如下:
下面用一个简单的留言板例子来实现一下MVC模型,功能是登录账号之后可以看到所有留言的内容。那么这个模型的业务流程大概就是:
首先在login页面输入账号和密码,再将输入的送到loginServlet中,loginServlet先调用Users类来验证账号和密码是否正确,若不正确则返回login重新输入;若正确则调用Message类来取出数据库中的所有留言信息,最后将这些留言信息送到MessageList页面显示出来。代码如下:
1、登录页面,账号与密码信息已经存到了数据库中,这里就不细说了。用户填好账号和密码之后将调用Servlet来处理请求。调用Servlet方法就是将表单的action设为Servlet的名字。本页面还加入了检查输入的函数,检查完之后再提交表单。
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="UTF-8" import="java.util.*"%>
用户登录
2、loginServlet,这个Servlet首先new一个Users对象,将该对象的属性值设成用户输入的账号和密码,再调用他的check方法来验证账号和密码是否正确。若不正确则返回重新登录;若正确则调用Message类来访问数据库,将所有留言信息存到一个List中,然后通过request的setAttribute方法将该List传递给MessageList.jsp页面上来显示。
PS:为了防止中文账号传过来之后乱码,加入request.setCharacterEncoding("utf-8");这一句,使JSP和此Servlet的字符集相同。否则程序会用乱码去和数据库中的账号做比较,结果肯定出错。
package com.servlet;
import java.io.IOException;
import java.util.*;
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 javax.swing.JOptionPane;
import com.bean.Message;
import com.bean.Users;
/**
* Servlet implementation class loginservlet
*/
@WebServlet("/loginservlet")
public class loginservlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public loginservlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
Users user = new Users();
String name = request.getParameter("username");
String password = request.getParameter("password");
user.setUsername(name);
user.setPassword(password);
if (!user.check()) {
JOptionPane.showMessageDialog(null, "用户名或密码错误! ", "登录失败 ", JOptionPane.ERROR_MESSAGE);
request.getRequestDispatcher("login.jsp").forward(request, response);
} else {
Message m = new Message();
List list = m.searchall();
request.setAttribute("list", list);
request.getRequestDispatcher("MessageList.jsp").forward(request, response);
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
3、Users和Message类,这是MVC中的JavaBean,用来实现数据库的数据存取。这两个类中我都调用了DButil这个类,这是个工具类,用来连接数据库,下面再说。
Users类,实现的功能是检查用户登录时输入的账号和密码是否正确,用户在输入账号和密码之后会定义一个Users对象,通过调用他的check()方法,来将输入的信息与数据库中的信息作对比。
验证账号密码的时候,我是先从数据库中,将用户输入的用户名所在的这一行取出来。若数据库中不存在输入的用户名,即结果集的行数为0,则登录失败(求结果集的行数之前必须先调用last方法);若有数据,但是数据库中存着的密码与输入的不符,则登录失败(java中判断两个字符串相等不能用==,要调用其中一个字符串的equal方法,getString用于取出该列的值)。
package com.bean;
import com.util.DButil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JOptionPane;
@SuppressWarnings("unused")
public class Users {
private String Username;
private String password;
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 boolean check() {
Connection conn = DButil.open();
String sql = "select * from user where name=" + "'" + this.Username + "'";
try {
PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery(sql);
rs.last();
int row = rs.getRow();
if (row == 0) {
JOptionPane.showMessageDialog(null, "无数据", "登录失败 ", JOptionPane.ERROR_MESSAGE);
return false;
}
if (!rs.getString(2).equals(this.password)) {
JOptionPane.showMessageDialog(null, "密码错误", "登录失败 ", JOptionPane.ERROR_MESSAGE);
return false;
}
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
return false;
}
return true;
}
}
Message类,实现的是将所有留言信息从数据库中读出来,返回一个List。
package com.bean;
import java.util.*;
import javax.swing.JOptionPane;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.util.DButil;
public class Message {
String title;
String context;
String author;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public List searchall() {
String sql = "select * from message";
Connection conn = DButil.open();
try {
PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery(sql);
List list = new ArrayList();
while (rs.next()) {
Message m = new Message();
m.setTitle(rs.getString(1));
m.setContext(rs.getString(2));
m.setAuthor(rs.getString(3));
list.add(m);
}
return list;
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return null;
}
}
4、MessageList.jsp,此页面用于显示从数据库中取出的所有留言信息。刚才在loginServlet中已经将结果集list传递了过来,那么我们这里就直接调用getAttribute方法来接收,再遍历输出即可。输出方法就是在java代码中插入HTML标签,一边遍历一边输出。代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.*" import="com.bean.Message"
import="javax.swing.*"%>
留言列表
留言列表
序号
标题
作者
操作
<%
List list = (List) request.getAttribute("list");
int i = 1;
for (Message m : list) {
%>
<%=i++%>
<%=m.getContext()%>
<%=m.getAuthor()%>
<%
}
%>
5、BDutil类,这是个工具类,只封装了一个方法,就是获取一个与数据库的连接Connection。代码如下:
package com.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
@SuppressWarnings("unused")
public class DButil {
private static String url = "jdbc:mysql://127.0.0.1:3306/实验?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false";// 连接数据库的驱动
private static String driver = "com.mysql.cj.jdbc.Driver";
private static String username = "root";
private static String password = "123456";
public static Connection open() {
try {
Class.forName(driver);
return (Connection) DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException | SQLException e) {
// TODO 自动生成的 catch 块
System.out.print("数据库打开失败!");
e.printStackTrace();
}
return null;
}
public static void close(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
实现效果大致如下,(一些前段的代码为了简练并没有贴上来,但实现功能的代码是齐全的):
1、用户登录
2、瞎输入用户名和密码的话会显示登录错误
3、登录成功后显示留言列表(第一条就是数据库中的数据,是我随便插入的):
前几天学习了DAO模式,然后才发现我的MVC其实不是很正宗的MVC,正宗的MVC是将与数据库做数据交换的函数放到了Servlet中,而我是放进了java bean中。然后我就更加感受到了MVC模式的弊端,Servlet本来是实现业务控制的地方,但是加入了与数据库的访问操作,这两个模块的耦合度太高了,不利于分工。
可能当时写这个留言板的时候已经感觉到这个问题了,所以我很自觉地把对数据库的访问放在了java bean中,但是今天回过头发现我这既不是DAO也不是MVC。我又写了一篇将MVC扩展为DAO的博客,可以很好地对数据层和控制层降耦,并将留言板的最终版本放到了GitHub上。
链接:https://blog.csdn.net/Q_M_X_D_D_/article/details/93315608