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.*"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>用户登录</title> </head> <script type="text/javaScript"> function checkLogin() { var username = document.getElementById("username_id"); if (username.value == "") { alert("请输入用户名!"); username.focus(); return; } var password = document.getElementById("password_id"); if (password.value == "") { alert("密码不能为空"); password.focus(); return; } login_form.submit(); } </script> <body> <center> <form name="login_form" action="loginservlet" method="post"> <table border=1> <tr> <td align="center" colspan=2 style="font-size: 30px">用户登录</td> </tr> <tr> <td>用户名:</td> <td><input type="text" id="username_id" name="username" size="25" /></td> </tr> <tr> <td>密 码:</td> <td><input type="password" id="password_id" name="password" size="25"></td> </tr> </table> <input type="button" value="登录" style="height: 30px; width: 80px" onclick="checkLogin()"> </form> </center> </body> </html>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<Message> 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<Message> searchall() { String sql = "select * from message"; Connection conn = DButil.open(); try { PreparedStatement ps = (PreparedStatement) conn.prepareStatement(sql); ResultSet rs = ps.executeQuery(sql); List<Message> list = new ArrayList<Message>(); 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.*"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>留言列表</title> </head> <body> <table align="center" border="1" width="50%" cellpadding="8"> <tr> <th align="center" colspan=6>留言列表</th> </tr> <tr> <th align="center" width=100>序号</th> <th align="center" width=500>标题</th> <th align="center" width=100>作者</th> <th align="center" width=100>操作</th> </tr> <% List<Message> list = (List<Message>) request.getAttribute("list"); int i = 1; for (Message m : list) { %> <tr align="center"> <td><%=i++%></td> <td><%=m.getContext()%></td> <td><%=m.getAuthor()%></td> <td> <form action="" method="post"> <input type="button" value="查看" onclick="" /> </form> </td> </tr> <% } %> </table> </body> </html>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+8&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