javaEE的设计模式
历史沿革:
1. model1(jsp + javaBean)
jsp承担了给用户显示和处理内部逻辑的任务,不安全,也不利于维护
2. model2 -> MVC(今天的主题)
Servlet + jsp + javaBean
关于model1和model2,这篇文章博主写的很详细:https://www.cnblogs.com/wzjhoutai/p/6829457.html
MVC
mvc是 一套设计模式, 里面主要是装饰模式
M - Model 模型 : javabean -> 业务模型 / 数据模型
V - View 视图 : jsp -> 负责单纯的页面显示
C - Controller 控制器 Servlet -> 处理用户请求 / 获取数据 / 调用业务模型, 拿到数据模型 / 传递数据 / 指定用哪个视图显示
MVC和三层架构的关系?
没啥关系
三层架构: web层 + service层 + dao层
MVC 发生在web层
mvc小项目实战:
实现如图所示购物网站
要求如下:
1.mvc设计模式
2.有分页效果
3.有商品详细信息页
商品详细信息页:
根据mvc设计模式思想,得出以下程序流程图
设计的分页效果流程图
分页效果的主要思想是建立一个泛型类PageBean,用于存放任何类型的商品信息以及在数据库中的记录数等
package com.wowowo.bean;
import java.util.List;
public class PageBean<T> {
// 存放当前页数
private int pageNum;
// 存放每页最大记录数
private int pageSize;
// 存放从哪一条记录开始读取,用于查询语句limit中
private int pageStart;
// 存放记录总数,用于末页按钮
private int pageMaxNum;
// 存放最大页数,用于末页按钮
private int pageMaxSize;
private List<T> data;
public PageBean(int pageNum, int pageSize, int pageMaxNum) {
super();
// 构造方法传三个成员属性,其余2个成员属性通过计算得出
this.pageNum = pageNum;
this.pageSize = pageSize;
this.pageMaxNum = pageMaxNum;
// 最大页数通过记录总数加上每页记录-1除以每页记录获得
// 1.每页5条 11条:3页=(15+5-1)/5; 15条:3页=(11+5-1)/5
pageMaxSize = (pageMaxNum + pageSize - 1) / pageSize;
// 另一种计算最大页数方法
// 先整除
// pageMaxSize=pageMaxNum/pageSize;
// 有余数就加1
// if(pageMaxNum%pageSize!=0){
// pageMaxSize++;
// }
/// 计算在数据库中执行查询语句时的初始位置
pageStart = (pageNum - 1) * pageSize;
}
//get, set,tostring方法略
}
用户访问首页,默认首页(localhost:8080/my1023hw)为index.jsp,因为只写了index.jsp(这个在web.xml配置中)
原因:
<welcome-file-list>用于指定应用的首页
里面可以指定多个文件,应用服务器会按从上到下的顺序搜索,如果找到就了进入该页面,如果都遍历完了还没找到就会返回404错误代码给浏览器。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>my1023hw</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
index.jsp(首页)
用户访问首页,它会请求转发到goodservlet(goodservlet设置了注解,和它相映射的url为/goods)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%-- 很重要:这个是jsp请求转发,给后端看的,不用加web项目名 --%>
<jsp:forward page="/goods"></jsp:forward>
</body>
</html>
goodsServlet(首页):
根据传入的当前页数和最大页数,调用service层和dao层方法查询记录并返回pagebean
package com.wowowo.web;
import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
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 org.eclipse.jdt.internal.compiler.parser.ParserBasicInformation;
import com.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.service.ProductService;
import com.wowowo.service.impl.ProductServiceImpl;
@WebServlet("/goods")
public class GoodsServlet extends HttpServlet {
// 依赖于业务逻辑层
private ProductService ps = new ProductServiceImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取用户上传的pageNum和pageSize
int pageNum = 1;
//pageNum放在了url中,get方法获取
String s_pageNum = request.getParameter("pageNum");
if (s_pageNum != null) {
pageNum = Integer.parseInt(s_pageNum);
}
int pageSize = 5;
//pageSize放在了url中,get方法获取
String s_pageSize = request.getParameter("pageSize");
if (s_pageSize != null) {
pageSize = Integer.parseInt(s_pageSize);
}
// 调用业务模型 获取数据模型
PageBean<Product> pageBean = ps.queryAll(pageNum, pageSize);
// 放到request域中
request.setAttribute("pageBean", pageBean);
// 转发到jsp页面
request.getRequestDispatcher("/main.jsp").forward(request, response);
}
}
service层(参考架构基础):
package com.wowowo.service.impl;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.dao.ProductDao;
import com.wowowo.dao.impl.ProductDaoImpl;
import com.wowowo.database.ConnectionFactory;
import com.wowowo.service.ProductService;
public class ProductServiceImpl implements ProductService {
private ProductDao pd = new ProductDaoImpl();
@Override
public PageBean<Product> queryAll(int pageNum, int pageSize) {
Connection conn = null;
List<Product> list = new ArrayList<>();
try {
conn = ConnectionFactory.getConnection();
// 查询获得记录数
int count = pd.queryCount(conn);
// 构造pageBean对象
PageBean<Product> pageBean = new PageBean<Product>(pageNum, pageSize, count);
//调用dao层方法查询相关记录,不返回值,在方法里面对pageBean修改
//传引用赋值和传值赋值的区别建议再看看
pd.queryAll(conn, pageBean);
return pageBean;
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
// 这个方法用于商品详情页面
@Override
public Product queryById(int uid) {
Connection conn = null;
List<Product> list = new ArrayList<>();
try {
conn = ConnectionFactory.getConnection();
return pd.queryById(conn, uid);
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
}
dao层用于和数据库交互(参考架构基础);
package com.wowowo.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.wowowo.bean.PageBean;
import com.wowowo.bean.Product;
import com.wowowo.dao.ProductDao;
import com.wowowo.database.ConnectionFactory;
public class ProductDaoImpl implements ProductDao {
// 查记录总数
@Override
public int queryCount(Connection conn) throws SQLException {
String sql = "select count(*)from product";
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getInt(1);
}
return 0;
}
// 根据这一页的的初始记录位置,和每页显示数量查找相关记录并组装成list赋值给pageBean,不用返回
@Override
public void queryAll(Connection conn, PageBean<Product> pageBean) throws SQLException {
List<Product> list = new ArrayList<>();
String sql = "select *from product limit ?,?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, pageBean.getPageStart());
ps.setInt(2, pageBean.getPageSize());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Product product = new Product();
product.setProdId(rs.getInt("prodId"));
product.setProdName(rs.getString("prodName"));
product.setProdImage(rs.getString("prodImage"));
product.setProdPrice(rs.getDouble("prodPrice"));
product.setProdAmount(rs.getInt("prodAmount"));
list.add(product);
}
pageBean.setData(list);
}
// 通过id查找商品,用于显示商品详情
@Override
public Product queryById(Connection conn, int uid) throws SQLException {
String sql = "select *from product where prodid =?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, uid);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Product product = new Product();
product.setProdId(rs.getInt("prodId"));
product.setProdName(rs.getString("prodName"));
product.setProdImage(rs.getString("prodImage"));
product.setProdPrice(rs.getDouble("prodPrice"));
product.setProdAmount(rs.getInt("prodAmount"));
return product;
}
return null;
}
}
对我而言,难点在于jsp页面,毕竟刚学
首页(main)的jsp(view层)
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.List"%>
<%@page import="com.wowowo.bean.*"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
<style type="text/css">
.prod {
border: 1px solid black;
width: 230px;
}
.prod_price {
float: right;
}
</style>
</head>
<body>
<h1 class="text-center">欢迎访问服装商城</h1>
<div class="container">
<%
//request域对象里拿到servlet传过来的数据模型,强转,拿出记录list
PageBean<Product> pageBean = (PageBean<Product>) request.getAttribute("pageBean");
//拿出商品list,遍历输出每一条记录
List<Product> list = pageBean.getData();
for (int i = 0; i < list.size(); i++) {
%>
<div class="prod col-md-3">
<div>
<%-- a标签的属性href属性用于指定超链接目标的URL,在url尾部添加?uid=商品id跳转到详细信息servlet --%>
<a href="/my1023hw/single?uid=<%=list.get(i).getProdId()%>"><img
<%-- 图片路径通过jsp脚本实现拼接 --%>
src="images/<%=list.get(i).getProdImage()%>" /></a>
</div>
<div>
<%
//商品名,也可以用脚本表达式 <%==list.get(i).getProdName()%》
out.write(list.get(i).getProdName());
%>
<span class="prod_price">价格:<%
//商品价格,也可以用脚本表达式 <%==list.get(i).getProdName()%》
out.write(String.valueOf(list.get(i).getProdPrice())); %>
</span>
</div>
</div>
<%
}
%>
<%-- 循环结束 --%>
</div>
<div style="text-align: center;">
<%--a标签的 href属性用于指定超链接目标的 URL,通过在后面添加?k-v&k-v在servlet的get方式能获取到参数--%>
<%-- 首页为第一页,url里输入首页和点击首页的效果一致,每页5条记录 --%>
<a href="goods?pageNum=1&pageSize=5" class="btn btn-danger">首页</a>
<%-- 上一页为当前页-1,前提是当前页不是第一页,采用三目运算符实现,每页5条记录 --%>
<a
href="goods?pageNum=<%=pageBean.getPageNum() <= 1 ? 1 : pageBean.getPageNum() - 1%>&pageSize=5"
class="btn btn-danger">上一页</a>
<%-- 下一页为当前页+1,前提是当前页不是末页,采用三目运算符实现,每页5条记录 --%>
<a
href="goods?pageNum=<%=pageBean.getPageNum() >= pageBean.getPageMaxSize() ? pageBean.getPageNum()
: pageBean.getPageNum() + 1%>&pageSize=5"
class="btn btn-danger">下一页</a>
<%-- 末页为在pagebean的构造方法中有计算,只需取出即可,每页5条记录 --%>
<a href="goods?pageNum=<%=pageBean.getPageMaxSize()%>&pageSize=5"
class="btn btn-danger">末页</a>
</div>
</body>
</html>
详细信息页面的设计:
在首页的商品图片设置a标签(商品id放在url中)跳转到singleservlet(get方式获取url中的参数商品id并做业务处理,返回一个数据模型放到request)转发到jsp显示
singleservlet(controller层)
package com.wowowo.web;
import java.io.IOException;
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 com.wowowo.bean.Product;
import com.wowowo.service.ProductService;
import com.wowowo.service.impl.ProductServiceImpl;
/**
* Servlet implementation class SingleServlet
*/
@WebServlet("/single")
public class SingleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private ProductService ps=new ProductServiceImpl();
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//get方式获取的商品id
int uid = Integer.parseInt(request.getParameter("uid"));
//传入逻辑模型
Product p=ps.queryById(uid);
//request添加数据模型
request.setAttribute("product", p);
//跳转到single.jsp(view层)
request.getRequestDispatcher("/single.jsp").forward(request, response);;
}
}
singleservlet跳转到的jsp(view层)
显示单一商品信息
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@page import="com.wowowo.bean.*"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
.single {
width: 500px;
text-align: center;
margin: auto;
}
.detail {
height: 195px;
float: left;
}
</style>
</head>
<body>
<%
Product p = (Product) request.getAttribute("product");
%>
<div class="single">
<div class="detail">
<img src="/my1023hw/images/<%=p.getProdImage()%>" />
</div>
<div class="detail">
商品名称:<%=p.getProdName()%><br /> 商品单价:<%=p.getProdPrice()%><br />
商品库存:<%=p.getProdAmount()%><br /> <input type="text" value="1">
<br /> <input type="button" value="添加到购物车"> <input
type="button" value="立即购买">
</div>
</div>
</body>
</html>