Java EE三层架构

分层目的是为了解耦,降低代码的耦合度。方便后期的维护和升级
建包:
项目编写顺序:
1.创建数据库和所需要的表
2.编写数据库对应的Javabean对象
3.编写JdbcUtils类
4.编写BaseDao
5.编写dao和测试
6.编写Service和测试
7.编写web层
web层编写servlet来处理service请求
调用service层方法来处理
注:web阶段使用 base 标签 加相对路径
框架阶段使用绝对路径
优化代码:
1 页面jsp动态化:将所有的html页面转为jsp页面
2 抽取页面中相同的部分
head中的 css、jQuery、base标签 (base标签要改为动态获取的)
每个页面的页脚
登录成功后的菜单
manager模块的菜单
3 登录 注册错误提示及表单回显
Servlet 程序端需要添加回显信息到 Request 域中
4 BaseServlet 的抽取
在实际的项目开发中,一个模块,一般只使用一个 Servlet 程序
如图 实现请求分发的功能
#使用反射优化大量 else if 对于方法的判断//原来if("login".equals(action)){login(request, response);}else if("regist".equals(action)){regist(request, response);}//现在try {Method method = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);method.invoke(this, request, response);} catch (Exception e) {e.printStackTrace();}
5 数据的封装和抽取 BeanUtils 的使用
BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。 BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。
//导包 commons-beanutils /commons-logging//编写工具类public static void fillBean(Object obj, Map map){try {BeanUtils.populate(obj, map);} catch (Exception e) {e.printStackTrace();}}//调用webUtils.fillBean(user,request.getParameterMap());
6 使用 EL 表达式修改表单回显
MVC 概念
MVC 全称:Model 模型、 View 视图、 Controller 控制器。
MVC 最早出现在 JavaEE 三层中的 Web 层,它可以有效的指导 Web 层的代码如何有效分离,单独工作。
View 视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作—— JSP/HTML。
Controller 控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。 转到某个页面。或者是重定向到某个页面。
Model 模型:将与业务逻辑相关的数据封装为具体的 JavaBean 类,其中不掺杂任何与数据处理相关的代码—— JavaBean/domain/entity/pojo
MVC 是一种思想 MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)
标签 发起是一个 get 请求
tips:如果访问jsp无法直接获取数据 那么可以让程序先访问servlet程序 再转发
- 添加图书功能实现:

表单重复提交: 当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户按下功能键 F5,就会发起浏览器记录的最后一次请求。所以添加图书要用请求重定向(发起的是两次请求)
- 删除图书功能的实现:
```javascript
//删除图书时 需要绑定单机事件 confirm 表示是否确认删除
$(function (){
$(“a.delclass”).click(function (){
}); });/*** confirm 是确认提示框函数* 参数是它的提示内容* 它有两个按钮,一个是确认,一个是取消* 返回true表示点击确认 返回false表示点击取消*/return confirm("确定要删除该图书吗?");
- **修改图书功能的实现:****动态修改隐藏域**:(既可以实现添加 又可以实现修改操作)<br />法一:可以在请求发起时,附带上当前要操作的值,并注入到隐藏域中<br />法二:通过判断当前参数中是否包含id参数。来判断是修改(有参数)还是添加(无参数)<br />法三:可以通过判断request域中是否包含有修改的图书实验对象<a name="Xpg24"></a>### 分页模块<br />**先分析出需要的对象模型(page),**再做业务需求。分页条跳到指定页数```javascript$(function (){$("#searchPageBtn").click(function (){var pageNo = $("#pn_input").val();//js语言中提供了一个 location 地址栏对象//它有一个属性 href ,它可以获取浏览器地址栏中的地址;//href属性 可读,可写location.href="manager/bookManager?action=page&pageNo="+pageNo;});});
注:再pageNo 注入之前要进行数据边界的检查(在bean对象set方法时设置)
//数据边界的有效检查if(pageNo<1){pageNo=1;}if(pageNo>pageTotal){pageNo=pageTotal;}
#分页条码的输出:
需求:显示 5 个连续的页码,而且当前页码在中间。除了当前页码之外,每个页码都可以点击跳到指定页。
- 情况 1:如果总页码小于等于 5 的情况,页码的范围是:1-总页码
1 页 1
2 页 1,2
3 页 1,2,3
4 页 1,2,3,4
5 页 1,2,3,4,5
- 情况 2:总页码大于 5 的情况。假设一共 10 页
- 小情况 1:当前页码为前面 3 个:1,2,3 的情况,页码范围是:1-5.
【1】2,3,4,5
1,【2】3,4,5
1,2,【3】4,5
- 小情况 2:当前页码为最后 3 个,8,9,10,页码范围是:总页码减 4 - 总页码
6,7【8】9,10
6,7,8【9】10
6,7,8,9【10】
- 小情况 3:4,5,6,7,页码范围是:当前页码减 2 - 当前页码加 2
2,3,【4】,5,6
3,4,【5】,6,7
4,5,【6】,7,8
5,6,【7】,8,9
//分页条的编写<div id="page_nav"><c:if test="${requestScope.page.pageNo>1}"><a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo-1}">上一页</a></c:if><%--页码输出的开始--%><c:choose><c:when test="${ requestScope.page.pageTotal <= 5 }"><c:set var="begin" value="1"/><c:set var="end" value="${requestScope.page.pageTotal}"/></c:when><c:when test="${requestScope.page.pageTotal > 5}"><c:choose><c:when test="${requestScope.page.pageNo <= 3}"><c:set var="begin" value="1"/><c:set var="end" value="5"/></c:when><c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}"><c:set var="begin" value="${requestScope.page.pageTotal-4}"/><c:set var="end" value="${requestScope.page.pageTotal}"/></c:when><c:otherwise><c:set var="begin" value="${requestScope.page.pageNo-2}"/><c:set var="end" value="${requestScope.page.pageNo+2}"/></c:otherwise></c:choose></c:when></c:choose><c:forEach begin="${begin}" end="${end}" var="i"><c:if test="${i == requestScope.page.pageNo}">【${i}】</c:if><c:if test="${i != requestScope.page.pageNo}"><a href="${requestScope.page.url}&pageNo=${i}">${i}</a></c:if></c:forEach><%--页码输出的结束--%><c:if test="${requestScope.page.pageNo<requestScope.page.pageTotal}"><a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo+1}">下一页</a></c:if>,共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录, 跳至第<input value="${requestScope.page.pageNo}" name="pn" id="pn_input"/>页<input id="searchPageBtn" type="button" value="确定"></div>
价格搜索区间:
用户登录的信息保存在sessionScope域中
注销用户:
1 销毁session中的用户登录信息
2 重定向会首页或者登录页面
//1 销毁session中的用户登录信息request.getSession().invalidate();//2 重定向会首页或者登录页面response.sendRedirect(request.getContextPath());
表单重复提交
表单重复提交有三种常见的情况:
1 提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键F5,就会发起最后一次的请求。造成表单重复提交问题
解决方法:使用重定向来进行跳转
2 用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候多点几次提交操作,也会造成表单重复提交
3 用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交
谷歌 kaptcha 图片验证码的使用
//配置xml文件<servlet><servlet-name>KaptchaServlet</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class></servlet><servlet-mapping><servlet-name>KaptchaServlet</servlet-name><url-pattern>/Kaptcha.jpg</url-pattern></servlet-mapping>//在表单中img标签去显示验证码并使用<img id="code_img" alt="" src="Kaptcha.jpg">#验证码的切换//给验证码的图片 绑定单击事件$(function (){$("#code_img").click(function (){//this 对象,表示当前正在响应事件的dom对象//src 属性表示验证码 img 标签的图片路径。它可读,可写this.src="${path}Kaptcha.jpg?d="+new Date();});});
购物车模块实现(使用session保存)
使用Filter过滤器实现后台的权限管理
<filter><filter-name>managerFilter</filter-name><filter-class>com.book.filter.managerFilter</filter-class></filter><filter-mapping><filter-name>managerFilter</filter-name><url-pattern>/pages/manager/*</url-pattern><url-pattern>/manager/bookServlet</url-pattern></filter-mapping>
error 标签配置错误页面
<error-page><error-code>404</error-code><location>/pages/error/error_404.jsp</location></error-page>
注:再收到异常后,要继续把异常往外抛,tomcat服务器收到异常后就会处理相应的错误代码页面
