文章目录
2.JSP实战优化:使用分层技术处理业务逻辑
2.1 软件分层概述
刚才我们在写代码的时候其实大家应该也能发现,JSP页面其实作为页面来说还是承载了它不该承载的很多东西,比如数据库操作
JSP作为请求发送 请求处理 数据展示的媒介,应该发挥它很好的请求与接收的任务,但是现在我们什么都用JSP去写,这样无形中增加了JSP的负担!
那么怎么缓解现在JSP的尴尬境地呢?这时候你就需要用分层原则来设计你的代码了!
2.1.1 为什么需要软件分层开发
JSP开发时分两层的弊端
既然分两层是有弊端的,那么我们就分三层来处理业务
2.2 软件分层原则(了解)
- 上层依赖其下层,依赖关系不跨层 : 表示层不能直接访问数据访问层;
- 上层调用下层的结果,取决于下层的实现 : 下一层不能调用上一层,下一层不依赖上一层;
- 上层的改变不会影响下一层, 下层的改变会影响上一层得到的结果
- 在上一层中不能出现下一层的概念 : 分工明确,各司其职
简单来说,我们要把以前我们都写道一起的代码都分开来写,一分多,然后用的时候再灵活组织到一起,这叫模块化设计;
这种模块化的思想是人类社会工业生产的普遍思想,通俗来说,你可以想一下,拿西红柿炒鸡蛋来说,为什么自然界提供的是
西红柿 和 鸡蛋 两种物质 而不直接提供西红柿炒鸡蛋这种物质呢?
2.3 软件分层优势
2.4 软件分层实施
重构我们的CURD项目
一般软件分层分为三层 数据层 业务层 控制层
- 数据层 叫做 DAO(Data Access Object)层 专门用来处理数据
- 业务层 叫做 Service/Business 层 专门用来处理业务逻辑
- 控制层 叫做 controller/WEB 层 专门负责页面的控制
DAO 层 和 Service层都是有接口和实现类这种设计原则实际的
接口负责设计本层的结构 实现类帮助其实现内容 并且使用接口也能减少类与类之间的耦合
所以我们现在的项目 可以把JSP中的代码抽取出来,放到DAO层和Service层这样JSP就可以专心做页面控制了;
顺便一提的是 除了 DAO层 service层 和 controller层之外 我们如果用到其他功能还可以分很多个其他层来操作
比如
专门存放实体类的 层 我们叫 实体层 用 entity 表示
专门存放工具类的 层 我们叫 工具层 用 utils 表示
所以此时我们要重构JSP的CURD项目 首先创建项目完事后我们应该这样分层(分包)开发项目
手动创建包太累?来在src上创建一个类叫AutoCreatePackage
一定要放在src包下 也就是显示(default package)
创建好类之后粘贴下面的代码
import java.io.File;
/**
* 自动创建包工具类
* @author My
*
*/
public class AutoCreatePackage {
public static void main(String[] args) {
// 获取src目录
String srcdir = System.getProperty("user.dir") + "\\src";
// 创建com包
File file = new File(srcdir + "\\com");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy包
file = new File(srcdir + "\\com\\hnxy");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.entity
file = new File(srcdir + "\\com\\hnxy\\entity");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.utils
file = new File(srcdir + "\\com\\hnxy\\utils");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.dao
file = new File(srcdir + "\\com\\hnxy\\dao");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.service
file = new File(srcdir + "\\com\\hnxy\\service");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.web
file = new File(srcdir + "\\com\\hnxy\\web");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.dao.impl
file = new File(srcdir + "\\com\\hnxy\\dao\\impl");
// 判断
if (!file.exists()) {
file.mkdir();
}
// 创建com.hnxy.service.impl
file = new File(srcdir + "\\com\\hnxy\\service\\impl");
// 判断
if (!file.exists()) {
file.mkdir();
}
System.out.println("所有包创建完毕,请选中src包按F5键!");
}
}
有的同学会问没有放在默认包下的话就会出现下面的报错
这时值需要点击movie…这个选项会自动移动到默认包下;
运行代码
运行好之后按提示 F5刷新即可!
效果
这几个包就都自动创建出来了
2.5 开始实现 :
2.5.1. 新项目导包,工具类,实体类编写
2.5.2 整理DAO层需求
根据整理我们可以知道,对于数据操作我们页面基本需要以下几个功能 :
- 查询全部数据
- 按ID查询数据
- 添加数据
- 修改数据
- 删除数据
这些功能我们一时还无法全部实现,但是我们可以用想法先将DAO层的结构定义好
代码:
package com.hnxy.dao;
import java.util.List;
import com.hnxy.entity.Person;
/**
* 人员表的数据库操作接口 意义 定义我们现在的思想
* @author My
*
*/
public interface PersonDAO {
/**
* 添加方法
* @param person 要添加的对象
* @return 返回1 代表添加成功 返回0 代表添加失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int insertPerson(Person person)throws Exception;
/**
* 更新方法
* @param person 要更新的对象
* @return 返回1 代表更新成功 返回0 代表更新失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int updatePerson(Person person)throws Exception;
/**
* 删除犯法
* @param person 要删除的对象
* @return 返回1 删除成功 返回0 删除失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int deletePerson(Person person)throws Exception;
/**
* 根据主键ID查询信息
* @param id 要查询的数据ID
* @return 查询到了 返回对象 没有查询到 返回null
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public Person findPersonByID(Integer id)throws Exception;
/**
* 查询全部
* @return 查询到了返回对象list 没有查询到返回null
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public List<Person> findAllPersons()throws Exception;
}
定义好结构之后我们再想办法去实现,对于接口的实现类,一般我们也会放到一个特定的包下,如果是dao层接口的实现类 就放在dao包下的impl包下
如果是service包下接口的实现类,就放在service的impl包下,所以PersonDAO的实现应该是这个样子的:
具体实现代码:
package com.hnxy.dao.impl;
import java.sql.Connection;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import com.hnxy.dao.PersonDAO;
import com.hnxy.entity.Person;
import com.hnxy.utils.JdbcUtil;
/**
* 数据库操作层的实现类
* @author My
*
*/
public class PersonDAOImpl implements PersonDAO {
@Override
public int insertPerson(Person person) throws Exception {
// 创建方法的返回值
int count = 0;
// 获取数据库连接
Connection conn = JdbcUtil.getConn();
// 创建SQL执行对象
QueryRunner qr = new QueryRunner();
// 编写SQL语句
String sql = "insert into person values (null,?,?,?,?)";
// 占位符赋值
Object[] params = {person.getName(),person.getSex(),person.getAge(),person.getFrom()};
// 执行
count = qr.update(conn,sql,params);
// 关闭
JdbcUtil.closeConn(conn);
// 返回
return count;
}
@Override
public int updatePerson(Person person) throws Exception {
// 创建方法的返回值
int count = 0;
// 获取数据库连接
Connection conn = JdbcUtil.getConn();
// 创建SQL的执行对象
QueryRunner qr = new QueryRunner();
// 编写SQL语句
String sql = "update person set `name`=?,`sex`=?,`age`=?,`from`=? where `id`=?";
// 占位符赋值
Object[] params = {person.getName(),person.getSex(),person.getAge(),person.getFrom(),person.getId()};
// 执行
count = qr.update(conn, sql,params);
// 关闭
JdbcUtil.closeConn(conn);
// 返回
return count;
}
@Override
public int deletePerson(Person person) throws Exception {
// 创建方法的返回值
int count = 0;
// 获取数据库连接
Connection conn = JdbcUtil.getConn();
// 创建SQL的执行对象
QueryRunner qr = new QueryRunner();
// 编写SQL语句
String sql = "delete from person where `id` = ?";
// 占位符赋值
Object[] params = {person.getId()};
// 执行
count = qr.update(conn, sql, params);
// 关闭
JdbcUtil.closeConn(conn);
// 返回
return count;
}
@Override
public Person findPersonByID(Integer id) throws Exception {
// 创建方法的返回值
Person person = null;
// 获取数据库连接
Connection conn = JdbcUtil.getConn();
// 创建SQL的执行对象
QueryRunner qr = new QueryRunner();
// 编写SQL语句
String sql = "select * from person where `id` = ?";
// 是否需要占位符赋值?
Object[] params = {id};
// 执行
person = qr.query(conn, sql,new BeanHandler<Person>(Person.class),params);
// 关闭连接
JdbcUtil.closeConn(conn);
// 返回
return person;
}
@Override
public List<Person> findAllPersons() throws Exception {
// 创建方法的返回值
List<Person> plist = null;
// 获取数据库连接
Connection conn = JdbcUtil.getConn();
// 创建SQL执行对象
QueryRunner qr = new QueryRunner();
// 编写SQL语句
String sql = "select * from person";
// 占位符赋值
// 执行
plist = qr.query(conn,sql,new BeanListHandler<Person>(Person.class));
// 关闭 spring 伟大的程序
JdbcUtil.closeConn(conn);
// 返回
return plist;
}
}
这样DAO层开发就完成了,其实我们可以看到就是这样分层开发更加规范更加符合面向对象思想,但是其复杂难度也随之增加,这也是分层开发不好的一点;
2.5.3 整理Service层需求
service 主要是承上启下 并且处理业务的层,所以此层基本都是为了承接DAO层向页面传递数据的;所以大多数情况下service层的编写完全可以参照DAO层来做
现阶段我们还属于JavaEE技术的婴儿期,所以作为一个婴儿哪有什么社会责任需要你去承担,所以我们的业务层根据就没有业务需要处理只需要完成承上启下就可以
Service接口的编写 :
package com.hnxy.service;
import java.util.List;
import com.hnxy.entity.Person;
/**
* 人员表的Service层接口
* @author My
*
*/
public interface PersonService {
/**
* 添加方法
* @param person 要添加的对象
* @return 返回1 代表添加成功 返回0 代表添加失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int insertPerson(Person person)throws Exception;
/**
* 更新方法
* @param person 要更新的对象
* @return 返回1 代表更新成功 返回0 代表更新失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int updatePerson(Person person)throws Exception;
/**
* 删除方法
* @param person 要删除的对象
* @return 返回1 删除成功 返回0 删除失败
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public int deletePerson(Person person)throws Exception;
/**
* 根据主键ID查询信息
* @param id 要查询的数据ID
* @return 查询到了 返回对象 没有查询到 返回null
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public Person findPersonByID(Integer id)throws Exception;
/**
* 查询全部
* @return 查询到了返回对象list 没有查询到返回null
* @throws Exception 声明一个我也不知道会报什么错的异常
*/
public List<Person> findAllPersons()throws Exception;
}
实现类的编写:
package com.hnxy.service.impl;
import java.util.List;
import com.hnxy.dao.PersonDAO;
import com.hnxy.dao.impl.PersonDAOImpl;
import com.hnxy.entity.Person;
import com.hnxy.service.PersonService;
/**
* 业务层实现类 主要做业务操作(针对客户的不同需求,然后调用DAO层完成数据封装)
*
* @author My
*
*/
public class PersonServiceImpl implements PersonService {
// 创建DAO层的对象
private PersonDAO personDAO = new PersonDAOImpl();
@Override
public int insertPerson(Person person) throws Exception {
return personDAO.insertPerson(person);
}
@Override
public int updatePerson(Person person) throws Exception {
return personDAO.updatePerson(person);
}
@Override
public int deletePerson(Person person) throws Exception {
return personDAO.deletePerson(person);
}
@Override
public Person findPersonByID(Integer id) throws Exception {
return personDAO.findPersonByID(id);
}
@Override
public List<Person> findAllPersons() throws Exception {
return personDAO.findAllPersons();
}
}
2.5.4 页面控制器整理
1) 查询全部的控制器
<%@page import="com.hnxy.entity.Person"%>
<%@page import="com.hnxy.service.impl.PersonServiceImpl"%>
<%@page import="com.hnxy.service.PersonService"%>
<%@page import="org.apache.commons.dbutils.handlers.BeanListHandler"%>
<%@page import="java.util.List"%>
<%@page import="org.apache.commons.dbutils.QueryRunner"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
// 创建service层对象
PersonService service = new PersonServiceImpl();
// 执行 查询 肯定获取一个model
List<Person> persons = service.findAllPersons();
// 保存模型 给 下一个页面展示
request.setAttribute("plist", persons);
// 转发
request.getRequestDispatcher("findAll_view.jsp").forward(request, response);
%>
2) 按ID查询的控制器
<%@page import="com.hnxy.entity.Person"%>
<%@page import="com.hnxy.service.impl.PersonServiceImpl"%>
<%@page import="com.hnxy.service.PersonService"%>
<%@page import="org.apache.commons.dbutils.handlers.BeanHandler"%>
<%@page import="org.apache.commons.dbutils.QueryRunner"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
// 删除业务
// 第一阶段 接收页面数据
// 1. 设定编码
request.setCharacterEncoding("UTF-8");
// 2. 接收数据
String pid = request.getParameter("pid");
// 第二阶段 数据库处理
PersonService service = new PersonServiceImpl();
Person person = service.findPersonByID(Integer.parseInt(pid));
// 第三阶段 服务器响应
// 保存要更新的信息
request.setAttribute("person", person);
// 转发给下一个页面展示person
request.getRequestDispatcher("update.jsp").forward(request, response);
%>
3) 添加的控制器
<%@page import="com.hnxy.entity.Person"%>
<%@page import="com.hnxy.service.impl.PersonServiceImpl"%>
<%@page import="com.hnxy.service.PersonService"%>
<%@page import="org.apache.commons.dbutils.QueryRunner"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
// 添加业务
// 作为控制器 就进行两步操作
// 1. 接收用户请求 2.调用model完成页面跳转控制即可
// 第一阶段 接收数据
// 1. 设定页面请求字符流的编码
request.setCharacterEncoding("UTF-8");
// 2. 接收页面数据
String pname = request.getParameter("pname");
String psex = request.getParameter("psex");
String age = request.getParameter("age");
String pfrom = request.getParameter("pfrom");
// 第二阶段数据库处理阶段
// 封装数据
Person person = new Person();
person.setAge(Integer.parseInt(age));
person.setName(pname);
person.setFrom(pfrom);
person.setSex(psex);
// 创建业务层对象
PersonService service = new PersonServiceImpl();
int count = service.insertPerson(person);
// 第三阶段 根据数据库的处理结果 进行相应结果处理
// 控制的要求 我给你一个person 你添加到数据库里 然后给我返回一个 0(添加失败) 或者 1(添加)
if(count > 0){
// 添加成功
// 重新定向到查询全部的页面
response.sendRedirect("findAll_server.jsp");
}else{
// 添加失败 response 响应流
String msg = "<script type='text/javascript'>history.go(-1);alert('添加失败!');</script>";
// 服务器想给客户端发送一段代码 让客户端知道添加失败了
// 你这段文字到底是什么类型的? text/html 那么浏览器就把你的这段话当做是HTML文本进行解析
response.setContentType("text/html; charset=UTF-8"); // 服务端给客户端发送的数据类型是什么
// 打印回去
out.print(msg);
}
%>
4) 更新的控制器
<%@page import="com.hnxy.service.impl.PersonServiceImpl"%>
<%@page import="com.hnxy.service.PersonService"%>
<%@page import="com.hnxy.entity.Person"%>
<%@page import="org.apache.commons.dbutils.QueryRunner"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 添加业务
// 第一阶段 接收数据
// 1. 设定页面请求字符流的编码
request.setCharacterEncoding("UTF-8");
// 2. 接收页面数据
String pname = request.getParameter("pname");
String psex = request.getParameter("psex");
String age = request.getParameter("age");
String pfrom = request.getParameter("pfrom");
String pid = request.getParameter("pid");
// 第二阶段数据库处理阶段
// 封装数据
// 创建业务层对象
PersonService service = new PersonServiceImpl();
Person person = service.findPersonByID(Integer.parseInt(pid));
if (null != person) {
person.setAge(Integer.parseInt(age));
person.setFrom(pfrom);
person.setId(Integer.parseInt(pid));
person.setName(pname);
person.setSex(psex);
int count = service.updatePerson(person);
// 第三阶段 根据数据库的处理结果 进行相应结果处理
if (count > 0) {
// 添加成功
// 重新定向到查询全部的页面
response.sendRedirect("findAll_server.jsp");
} else {
// 添加失败 response 响应流
String msg = "<script type='text/javascript'>history.go(-1);alert('更新失败!');</script>";
// 服务器想给客户端发送一段代码 让客户端知道添加失败了
// 你这段文字到底是什么类型的? text/html 那么浏览器就把你的这段话当做是HTML文本进行解析
response.setContentType("text/html; charset=UTF-8"); // 服务端给客户端发送的数据类型是什么
// 打印回去
out.print(msg);
}
} else {
// 添加失败 response 响应流
String msg = "<script type='text/javascript'>history.go(-1);alert('没有查询到要更新的数据!');</script>";
// 服务器想给客户端发送一段代码 让客户端知道添加失败了
// 你这段文字到底是什么类型的? text/html 那么浏览器就把你的这段话当做是HTML文本进行解析
response.setContentType("text/html; charset=UTF-8"); // 服务端给客户端发送的数据类型是什么
// 打印回去
out.print(msg);
}
%>
5) 删除的控制器
<%@page import="com.hnxy.service.impl.PersonServiceImpl"%>
<%@page import="com.hnxy.service.PersonService"%>
<%@page import="com.hnxy.entity.Person"%>
<%@page import="org.apache.commons.dbutils.QueryRunner"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 添加业务
// 第一阶段 接收数据
// 1. 设定页面请求字符流的编码
request.setCharacterEncoding("UTF-8");
// 2. 接收页面数据
String pid = request.getParameter("pid");
// 第二阶段数据库处理阶段
// 封装数据
// 创建业务层对象
PersonService service = new PersonServiceImpl();
Person person = service.findPersonByID(Integer.parseInt(pid));
if (null != person) {
int count = service.deletePerson(person);
// 第三阶段 根据数据库的处理结果 进行相应结果处理
if (count > 0) {
// 添加成功
// 重新定向到查询全部的页面
response.sendRedirect("findAll_server.jsp");
} else {
// 添加失败 response 响应流
String msg = "<script type='text/javascript'>history.go(-1);alert('删除失败!');</script>";
// 服务器想给客户端发送一段代码 让客户端知道添加失败了
// 你这段文字到底是什么类型的? text/html 那么浏览器就把你的这段话当做是HTML文本进行解析
response.setContentType("text/html; charset=UTF-8"); // 服务端给客户端发送的数据类型是什么
// 打印回去
out.print(msg);
}
} else {
// 添加失败 response 响应流
String msg = "<script type='text/javascript'>history.go(-1);alert('没有查询到要删除的数据!');</script>";
// 服务器想给客户端发送一段代码 让客户端知道添加失败了
// 你这段文字到底是什么类型的? text/html 那么浏览器就把你的这段话当做是HTML文本进行解析
response.setContentType("text/html; charset=UTF-8"); // 服务端给客户端发送的数据类型是什么
// 打印回去
out.print(msg);
}
%>
2.5 设计框架思维方式
2.5 层级之间的关系