前言:最近学习了三层架构模式,学完之后做了个小练习,在这里对该项目所学到的知识做一个总结。
一、 什么是三层架构模式
1、三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer)。
通常也称为:Web层、Service层、Dao层
2、区分层次的目的即为了 “高内聚低耦合” 的思想。在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层(又或称为领域层)、表示层。
a. 表示层:
界面层也称为表示层,位于最外层(最上层),离用户最近。用于显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面。
b. 业务逻辑层:
业务逻辑层(Business Logic Layer)无疑是系统架构中体现核心价值的部分。它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计,也即是说它是与系统所应对的领域(Domain)逻辑有关,很多时候,也将业务逻辑层称为领域层。
b. 数据访问层:
数据访问层,有时候也称为是持久层,其功能主要是负责数据库的访问,可以访问数据库系统、二进制文件、文本文档或是XML文档。简单的说法就是实现对数据表的select、insert、update以及delete的操作。如果要加入ORM的元素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化。
3、三层与MVC的区别:
很多人容易把三层模式与MVC模式混淆,三层与MVC的最不同的地方在于三层是没有Controller控制器的概念。虽然同样是架构级别的,三层与MVC相同的地方在于他们都有一个表现层,但是他们不同的地方在于其他的两个层。MVC没有把业务的逻辑访问看成两个层,这是采用三层架构或MVC搭建程序最主要的区别。当然了,在三层中也提到了Model概念,但是三层架构中Model的概念与MVC中Model的概念是不一样的,“三层” 中典型的Model层是以实体类构成的,而MVC里,则是由业务逻辑与访问数据组成的。
二、需求分析
完成一个小型用户管理系统,效果图如下:
1、管理员登录功能
2、简单功能:对用户的增删改、查询所有功能(该功能在后期完善分页显示功能后被去掉)
3、较复杂功能:批量删除、分页显示、多条件查询
三、技术选择
1、Web层:HTML, CSS, JavaScript, JSP, Servlet, BootStrap框架
2、Service层:Java
3、Dao层:MySQL, JDBC, Durid, JdbcTemplate
4、服务器:Tomcat8
5、JDK版本:1.8
四、数据库设计
数据库设计较为简单,一共为两张表:
1、管理员表
2、用户表
五、项目环境搭建
1、创建项目
2、导入所需jar包
3、按照规范分别创建包
六、简单功能的实现(只总结实现方式)
(一)登录功能
(二)查询所有功能
(三)添加功能
(四)删除功能
(五)修改功能
七、较复杂功能实现
(一)批量删除
(二)分页显示
1、参数分析
2、结构分析
(三)多条件查询
1、参数分析
2、流程分析只需要在分页查询功能上加上查询参数即可,故未画出
八、需要注意的点
(一)登录功能:
1、前后端使用什么传递参数?
答:通常会创建对应的JavaBean对象来传递参数
2、如何达到点击验证码图片刷新验证码的效果?
答:可以在请求验证码的超链接中加入图片标签,给超链接的请求地址设置为一个js函数,当用户点击图片时,执行该js函数动态更换验证码的请求地址(加入时间戳防止浏览器缓存)。
1 | <a href="javascript:refreshCode()"> |
1 | <script type="text/javascript"> |
3、从session域中获取到正确的验证码之后记得销毁,否则验证码将毫无实际作用!!!
1 | //获取正确的验证码 |
4、后台获取不到参数的常见原因:
a. 前端表单中提交的参数没有添加name属性
b. 在后端取参数时,使用的参数名错误
(二)查找所有功能
1、如何将后台查询到的多条用户信息返回给前台?
答:在本项目中使用的是List集合
1 | /** |
2、前台如何将获取到的用户信息进行显示?
答:在本项目中是在jsp中使用JSTL标签中的forEach标签进行遍历显示的
1 | <c:forEach items="${pageBean.pageContent}" var="user" varStatus="s"> |
(三)删除用户功能:
1、如何提交需要删除用户的id
答:因为在删除用户时,需要收到管理员的确定,所以将其安排在了一个js函数中进行传递。
1 | <a class="btn btn-default btn-sm" href="javascript:checkdelete(${user.id});">删除</a></td> |
1 | function checkdelete(id) { |
(四)修改功能:
1、修改的前提是什么?
答:在修改之前需要先向管理员显示该用户已有的信息。
2、修改的表单如果不做处理,在提交时是没有用户id的,那么如何进行id的传递?
答:虽然表单中没有显示提供,但是我们可以通过给表单添加隐藏项来解决这一问题。
1 | <form action="${pageContext.request.contextPath}/UpdateUserServlet" method="post"> |
(五)批量删除功能
1、如何实现全选功能?
答:判断全选按钮是否选中,如果是则让所有用户都被选中
1 | document.getElementById("selectAll").onclick = function () { |
2、每一个用户的id属性都在表格中,那么如何传递这些参数?
答:可以在table外层套一个form就可以了
1 | <form id="form" action="${pageContext.request.contextPath}/DelSelectedServlet" method="post"> |
(六)分页显示功能
1、要实现分页功能,前后端分别需要传递什么参数?
前端->后端:
a. 当前请求的页数
b. 每页显示的记录条数
后端->前端:
a. 总记录数
b. 总页数
c. 每页的记录
这些参数都以JavaBean的形式进行传递
2、分页条如何实现?
答:本项目使用的是BootStrap框架中的组件实现的
3、如何传递当前请求页的页码?
答:在每个页码按钮(实际上是超链接)的请求地址后面加上对应的页码这一参数即可
4、如何设置当前页为激活状态?
答:因为后端在封装请求参数时会把currentPage这一参数封装到pageBean(前后端传递参数的bean对象)中,所以在响应请求内容时,对应的pageBean中已经存在了请求的页码。那么在进行加载分页条的时候,可以通过遍历来判断哪一个分页按钮所对应的页码和请求时的currentPage相等,将相等的那一个按钮置为激活状态即可。
5、第一次请求时,并不会传递请求页码和每行记录数,那么如何设置?
答:在处理分页显示的servlet中,首先判断请求页和每页显示记录数这两个参数是否为空(null或者””),如果为空就表示为第一次请求,那么只需要在封装参数前,将这两个请求参数置为默认值即可。
6、在当前页已经为第一页或者最后一页时,如何处理“上一页”和“下一页”按钮?
答:如何当前页已经为第一页或者最后一页时,需要禁用这两个按钮,否则会出现错误。只需要对当前页码进行判断,是否为第一页或者最后一页,如果是则将“上一页”和“下一页”按钮置为不可用状态,并将其请求地址置为’#’
1 | <c:if test="${pageBean.currentPage == 1}"> |
7、计算limit中的start参数?
答:(当前页-1)* 每页记录数
8、计算总页数?
1 | int pageCount = (totalCount%rows==0)?(totalCount/rows):(totalCount/rows)+1; |
(七)条件查询功能
1、如何传递多个查询条件?
答:因为每个查询条件都是键值对,所以使用Map传递
2、如何拼接动态SQL?
答:在拼接SQL时,使用where 1=1; 这个条件始终为True,在不定数量查询条件情况下,1=1可以很方便的生成动态SQL语句。
1 | public List<User> findPageContent(int start, int rows, Map<String, String[]> condition) { |
3、如何实现查询条件的回显?
答:因为这些查询条件的封装都是在servlet中处理的,所以只需要在响应时,将这些查询条件也放到request域中,然后在显示查询结果的同时将查询条件也进行显示即可。
(八)补充
九、总结
通过这个小项目学到了以下几点:
1、项目的大致开发流程
2、如何使用三层架构模式
3、对每一个功能如何进行详细的分析
Java新手,若有错误,欢迎指正!