本栏博客目录
Serlvet笔记一(Servlet基础) Servlet笔记二(请求和响应) Servlet笔记三(会话及其会话技术) Servlet笔记四(JSP技术) Servlet笔记五(EL表达式和JSTL) Servlet笔记六(Servlet 高级) Servlet笔记七(JDBC) Servlet笔记八(数据库连接池与DBUtils工具) Servlet笔记九(JSP 开发模型)
JSP技术在Web应用程序的开发过程中运用十分广泛,它功能强大,是当前流行的动态网页技术标准之一。使用JSP技术开发Web应用程序,有两种开发模型可供选择,通常我们称为JSPModel1和JSPModel2。
JSP 开发模型
JSP 的开发模型即 JSP Model,在Web开发中,为了更方便地使用JSP技术,SUN公司为 JSP 技术提供了两种开发模型: JSP Model1 和 JSP Model2。JSP Model1 简单轻便,适合小型 Web 项目的快速开发;JSPModel2 模型是在 JSPModel1 的基础上提出的,它提供了更清晰的代码分层,更适用于多人合作开发的大型 Web 项目,实际开发过程中可以根据项目需求,选择合适的模型。
1. JSP Model1
在早期使用 JSP 开发的 JavaWeb 应用中,JSP 文件是一个独立的、能自主完成所有任务的模块,它负责处理业务逻辑、控制网页流程和向用户展示页面等,JSP 早期模型的工作原理,如图所示。
从图中可以看出,首先浏览器会发送请求给 JSP,然后 JSP 会直接对数据库进行读取、保存或修改等操作,最后 JSP 会将操作结果响应给浏览器。但是在程序中,JSP 页面功能的 “过于复杂” 会给开发带来一系列的问题,比如 JSP 页面中 HTML 代码和 Java 代码强耦合在一起, 使得代码的可读性很差;数据、业务逻辑、控制流程混合在一起,使得程序难以修改和维护。为了解决上述问题,SUN 公司提供了一种JSP开发的架构模型:JSPModel1。JSP Model1 采用 JSP + JavaBean 的技术,将页面显示和业务逻辑分开。其中,JSP 实现流程控制和页面显示,JavaBean 对象封装数据和业务逻辑。接下来通过一张图来描述 JSPModel1 的工作原理,如图所示。
从图中可以看出,JSPModel1 模型将封装数据和处理数据的业务逻辑交给了 JavaBean 组件,JSP只负责接收用户请求和调用 JavaBean 组件来响应用户的请求。这种设计实现了数据、业务逻辑和页面显示的分离,在一定程度上实现了程序开发的模块化,降低了程序修改和维护的难度。
2. JSP Model2
JSPModel1 虽然将数据和部分的业务逻辑从 JSP 页面中分离出去,但是 JSP 页面仍然需要负责流程控制和产生用户界面。对于一个业务流程复杂的大型应用程序来说,在 JSP 页面中依旧会嵌入大量的 Java 代码,这样会给项目管理带来很大的麻烦。为了解决这样的问题,SUN 公司在 Model1 的基础上又提出了 JSPModel2 架构模型。 JSP Model2架构模型采用 JSP + Servlet + JavaBean 的技术,此技术将原本 JSP 页面中的流程控制代码提取出来,封装到 Servlet 中,从而实现了整个程序页面显示、流程控制和业务逻辑的分离。实际上,JSP Model2 模型就是 MVC (模型Model - 视图View - 控制器Controller)设计模式。其中,控制器的角色是由 Servlet 实现的,视图的角色是由 JSP 页面实现的,模型的角色是由 JavaBean 实现的。JSP Model2的工作原理,如图所示。
从图中可以看出,Servlet 充当了控制器的角色,它首先接收浏览器发送的请求,然后根据请求信息实例化 JavaBean 对象来封装操作数据库后返回的数据,最后选择相应的 JSP 页面将响应结果显示在浏览器中。
MVC 设计模式
MVC 设计模式,它是施乐帕克研究中心在 20 世纪 80 年代为编程语言 Smalltalk–80 发明的一种软件设计模式,提供了一种按功能对软件进行模块划分的方法。MVC 设计模式将软件程序分为 3 个核心模块:模型( Model ) 视图( View ) 和 控制器( Controller ),这3个模块的作用如下所示。
1.模型
模型(Model) 负责管理应用程序的业务数据、定义访问控制以及修改这些数据的业务规则。当模型的状态发生改变时,它会通知视图发生改变,并为视图提供查询模型状态的方法。
2.视图
视图(View) 负责与用户进行交互,它从模型中获取数据向用户展示,同时也能将用户请求传递给控制器进行处理。当模型的状态发生改变时,视图会对用户界面进行同步更新,从而保持与模型数据的一致性。
3.控制器
控制器( Controller ) 是负责应用程序中处理用户交互的部分,它负责从视图中读取数据,控制用户输入,并向模型发送数据。
在图中,当控制器接收到用户的请求后,会根据请求信息调用模型组件的业务方法,对业务方法处理完毕后,再根据模型的返回结果选择相应的视图组件来显示处理结果和模型中的数据。
按照 Model2 思想实现用户注册功能
任务目标 学会使用 JSP Model2 模型开发程序。 JSP Model2 模型是一种 MVC 设计模式,由于 MVC 模式中的功能模块相互独立,并且使用该模式的软件具有极高的可维护性、可扩展性和可复用性,因此,使用MVC 开发模式的 Web应用越来越受到欢迎。接下来,本任务将按照 JSP Model2 的模型思想编写一个用户注册程序。该程序中包含两个 JSP 页面 register.jsp 和loginSuccess jsp、一个 Servlet类ControllerServlet。两个 JavaBean 类RegisterFormBean 和 UserBean,以及一个访问数据库的辅助类 DBUtil,这 些组件的关系如图所示。
关于各个程序组件的功能和相互之间的工作关系介绍如下。 ( 1 ) UserBean 是代表用户信息的 JavaBean,ControllerServlet 根据用户注册信息创建出一个UserBean对象,并将对象添加到 DBUtil 对象中,loginSuccess.jsp 页面从 UserBean 对象中提取用户信息进行显示。 ( 2 ) RegisterFormBean 是封装注册表单信息的 JavaBean,用于对从 ControllerServlet 中获取到的注册表单信息中的各个属性(也就是注册表单内的各个字段中所填写的数据)进行校验。 ( 3 ) DBUtil 是用于访问数据库的辅助类,它相当于一个 DAO (数据访问对象)。 ( 4 ) ControllerServlet 是控制器,它负责处理用户注册的请求。如果注册成功,就会跳到 loginSuccess.jsp页面;如果注册失败,重新跳回到 register.jsp 页面并显示错误信息。 ( 5 ) register.jsp 是显示用户注册表单的页面,它将注册请求提交给 ControllerServlet 程序处理。 ( 6 ) loginSuccess.jsp 是用户登录成功后进入的页面,新注册成功的用户自动完成登录,直接进入 loginSuccess.jsp 页面。
项目结构
1. 编写 JavaBean
UserBean.java
package com.xxx.domain;
public class UserBean {
private String name;
private String password;
private String email;
private int uid;
public UserBean() {
}
public UserBean(String name, String password, String email) {
this.name = name;
this.password = password;
this.email = email;
}
@Override
public String toString() {
return "UserBean{" +
"name='" + name + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
RegisterFormBean
package com.xxx.domain;
import java.util.HashMap;
import java.util.Map;
public class RegisterFormBean {
private String name;
private String password;
private String password2;
private String email;
private Map<String, String> errs = new HashMap<>();
public RegisterFormBean() {
}
public RegisterFormBean(String name, String password, String password2, String email) {
this.name = name;
this.password = password;
this.password2 = password2;
this.email = email;
}
public boolean validate(){
boolean flag = true;
if(name == null || name.equals("")){
errs.put("name", "用户名不能为空");
flag = false;
}
if(password == null || password.equals("")){
errs.put("password", "密码不能为空");
flag = false;
}else if(password.length() < 6 || password.length() > 12){
errs.put("password", "输入的密码长度必须为6-12位");
flag = false;
}
if(password !=null && !password.equals(password2)){
errs.put("password2", "两次输入的密码不一致");
flag = false;
}
if(email == null || email.equals("")){
errs.put("email", "邮箱不能为空");
flag = false;
}else if(!email.matches("[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+")){
errs.put("email", "邮箱的输入格式错误");
flag = false;
}
return flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPassword2() {
return password2;
}
public void setPassword2(String password2) {
this.password2 = password2;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Map<String, String> getErrs() {
return errs;
}
public void setErrsMsg(String err, String errMsg) {
if(err != null && errMsg != null){
errs.put(err, errMsg);
}
}
}
2. 创建工具类
DBCPUtils.java
package com.xxx.util;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class DBCPUtils {
public static DataSource ds;
static {
Properties prop = new Properties();
try{
InputStream ins = new DBCPUtils().getClass().getClassLoader().getResourceAsStream("dbcp.properties");
prop.load(ins);
ds = BasicDataSourceFactory.createDataSource(prop);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
dbcp.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/javatask?useUnicode=true&characterEncoding=utf8
username=root
password=root
initialSize=5
maxInitial=10
maxIdle=5
DBUtilDao
package com.xxx.util;
import com.xxx.domain.UserBean;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import java.sql.SQLException;
import java.util.List;
public class DBUtilDao {
public UserBean find(String name) throws SQLException{
QueryRunner runner = new QueryRunner(DBCPUtils.ds);
String sql = "select * from usertb where name=?";
UserBean user = runner.query(sql, new BeanHandler<>(UserBean.class),new Object[]{name});
return user;
}
public Boolean insert(UserBean user) throws SQLException{
String name = user.getName();
UserBean u2 = find(name);
if(u2 != null) return false;
QueryRunner runner = new QueryRunner(DBCPUtils.ds);
String sql = "insert into usertb (name,password,email) values (?,?,?)";
int num = runner.update(sql, new Object[]{user.getName(), user.getPassword(),user.getEmail()});
if(num > 0) return true;
return false;
}
}
3. 创建 Servlet
ControllerServlet
package com.xxx.web;
import com.xxx.domain.RegisterFormBean;
import com.xxx.domain.UserBean;
import com.xxx.util.DBUtilDao;
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("/ControllerServlet")
public class ControllerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
String name = req.getParameter("name");
String password = req.getParameter("password");
String password2 = req.getParameter("password2");
String email = req.getParameter("email");
RegisterFormBean formBean = new RegisterFormBean(name, password, password2, email);
if(!formBean.validate()){
req.setAttribute("formBean", formBean);
req.getRequestDispatcher("/register.jsp").forward(req, resp);
return;
}
UserBean user = new UserBean(name, password, email);
DBUtilDao dbdao = new DBUtilDao();
boolean flag = false;
try {
flag = dbdao.insert(user);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
if(!flag){
req.setAttribute("DBMesg", "您输入的用户已存在");
req.getRequestDispatcher("/register.jsp").forward(req, resp);
return;
}
req.getSession().setAttribute("userBean", user);
resp.getWriter().print("恭喜你注册成功,3秒种后自动跳转");
resp.setHeader("refresh", "3;url=successful.jsp");
}
}
4. 创建 JSP 页面
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>用户注册</title>
<style type="text/css">
h3{
margin-left: 100px;
}
#outer{
width: 750px;
}
span{
color: #ff0000;
}
div{
height: 20px;
margin-bottom: 10px;
}
.ch{
width: 80px;
text-align: right;
float: left;
}
.ip{
width: 500px;
float: left;
}
.ip>input{
margin-right: 20px;
}
#bt{
margin-left: 50px;
}
#bt>input{
margin-right: 30px;
}
</style>
</head>
<body>
<form action="/ControllerServlet" method="post">
<h3>用户注册</h3>
<div id="outer">
<div>
<div class="ch">姓名:</div>
<div class="ip">
<input type="text" name="name" value="${formBean.name}" />
<span> ${formBean.errs.name}${DBMesg}</span>
</div>
</div>
<div>
<div class="ch">密码:</div>
<div class="ip">
<input type="password" name="password" />
<span>${formBean.errs.password}</span>
</div>
</div>
<div>
<div class="ch">确认密码:</div>
<div class="ip">
<input type="password" name="password2" />
<span>${formBean.errs.password2}</span>
</div>
</div>
<div>
<div class="ch">邮箱:</div>
<div class="ip">
<input type="email" name="email" />
<span>${formBean.errs.email}</span>
</div>
</div>
<div id="bt">
<input type="reset" value="重置">
<input type="submit" value="注册">
</div>
</div>
</form>
</body>
</html>
successful.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login successfully</title>
<style type="text/css">
#main{
width: 500px;
height: auto;
}
#main div{
width: 200px;
height: auto;
}
ul{
padding-top: 1px;
padding-left: 1px;
list-style: none;
}
</style>
</head>
<body>
<%
if(session.getAttribute("userBean") == null){
%>
<jsp:forward page="register.jsp" />
<%
return;
}
%>
<div id="main">
<div id="welcome">恭喜你,登录成功</div>
<hr />
<div>您的信息</div>
<div>
<ul>
<li>您的姓名:${userBean.name}</li>
<li>您的邮箱:${userBean.email}</li>
</ul>
</div>
</div>
</body>
</html>
5. 运行结果
|