Java EE三层架构

image.png
分层目的是为了解耦,降低代码的耦合度。方便后期的维护和升级
建包:
image.png

项目编写顺序:

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 程序
image.png
如图 实现请求分发的功能

  1. #使用反射优化大量 else if 对于方法的判断
  2. //原来
  3. if("login".equals(action)){
  4. login(request, response);
  5. }else if("regist".equals(action)){
  6. regist(request, response);
  7. }
  8. //现在
  9. try {
  10. Method method = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
  11. method.invoke(this, request, response);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }

5 数据的封装和抽取 BeanUtils 的使用
BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。 BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。

  1. //导包 commons-beanutils /commons-logging
  2. //编写工具类
  3. public static void fillBean(Object obj, Map map){
  4. try {
  5. BeanUtils.populate(obj, map);
  6. } catch (Exception e) {
  7. e.printStackTrace();
  8. }
  9. }
  10. //调用
  11. 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程序 再转发

  • 添加图书功能实现:

image.png
表单重复提交: 当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户按下功能键 F5,就会发起浏览器记录的最后一次请求。所以添加图书要用请求重定向(发起的是两次请求)

  • 删除图书功能的实现: ```javascript //删除图书时 需要绑定单机事件 confirm 表示是否确认删除 $(function (){ $(“a.delclass”).click(function (){
    1. /**
    2. * confirm 是确认提示框函数
    3. * 参数是它的提示内容
    4. * 它有两个按钮,一个是确认,一个是取消
    5. * 返回true表示点击确认 返回false表示点击取消
    6. */
    7. return confirm("确定要删除该图书吗?");
    }); });
  1. - **修改图书功能的实现:**
  2. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1605477/1625923717995-927e3e87-3979-4fcf-b237-e8fb8e6c6968.png#height=468&id=H1hLq&margin=%5Bobject%20Object%5D&name=image.png&originHeight=842&originWidth=1756&originalType=binary&ratio=1&size=1091400&status=done&style=none&width=975)
  3. **动态修改隐藏域**:(既可以实现添加 又可以实现修改操作)<br />法一:可以在请求发起时,附带上当前要操作的值,并注入到隐藏域中<br />法二:通过判断当前参数中是否包含id参数。来判断是修改(有参数)还是添加(无参数)<br />法三:可以通过判断request域中是否包含有修改的图书实验对象
  4. <a name="Xpg24"></a>
  5. ### 分页模块
  6. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/1605477/1625983373623-b780770f-8c2b-441b-a38b-99c8d34d68af.png#height=421&id=zeFJn&margin=%5Bobject%20Object%5D&name=image.png&originHeight=622&originWidth=1508&originalType=binary&ratio=1&size=1058482&status=done&style=none&width=1021)<br />**先分析出需要的对象模型(page),**再做业务需求。
  7. 分页条跳到指定页数
  8. ```javascript
  9. $(function (){
  10. $("#searchPageBtn").click(function (){
  11. var pageNo = $("#pn_input").val();
  12. //js语言中提供了一个 location 地址栏对象
  13. //它有一个属性 href ,它可以获取浏览器地址栏中的地址;
  14. //href属性 可读,可写
  15. location.href="manager/bookManager?action=page&pageNo="+pageNo;
  16. });
  17. });

注:再pageNo 注入之前要进行数据边界的检查(在bean对象set方法时设置)

  1. //数据边界的有效检查
  2. if(pageNo<1){
  3. pageNo=1;
  4. }
  5. if(pageNo>pageTotal){
  6. pageNo=pageTotal;
  7. }

#分页条码的输出:
需求:显示 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

  1. //分页条的编写
  2. <div id="page_nav">
  3. <c:if test="${requestScope.page.pageNo>1}">
  4. <a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo-1}">上一页</a>
  5. </c:if>
  6. <%--页码输出的开始--%>
  7. <c:choose>
  8. <c:when test="${ requestScope.page.pageTotal <= 5 }">
  9. <c:set var="begin" value="1"/>
  10. <c:set var="end" value="${requestScope.page.pageTotal}"/>
  11. </c:when>
  12. <c:when test="${requestScope.page.pageTotal > 5}">
  13. <c:choose>
  14. <c:when test="${requestScope.page.pageNo <= 3}">
  15. <c:set var="begin" value="1"/>
  16. <c:set var="end" value="5"/>
  17. </c:when>
  18. <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}">
  19. <c:set var="begin" value="${requestScope.page.pageTotal-4}"/>
  20. <c:set var="end" value="${requestScope.page.pageTotal}"/>
  21. </c:when>
  22. <c:otherwise>
  23. <c:set var="begin" value="${requestScope.page.pageNo-2}"/>
  24. <c:set var="end" value="${requestScope.page.pageNo+2}"/>
  25. </c:otherwise>
  26. </c:choose>
  27. </c:when>
  28. </c:choose>
  29. <c:forEach begin="${begin}" end="${end}" var="i">
  30. <c:if test="${i == requestScope.page.pageNo}">
  31. ${i}】
  32. </c:if>
  33. <c:if test="${i != requestScope.page.pageNo}">
  34. <a href="${requestScope.page.url}&pageNo=${i}">${i}</a>
  35. </c:if>
  36. </c:forEach>
  37. <%--页码输出的结束--%>
  38. <c:if test="${requestScope.page.pageNo<requestScope.page.pageTotal}">
  39. <a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo+1}">下一页</a>
  40. </c:if>
  41. ,共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录, 跳至第<input value="${requestScope.page.pageNo}" name="pn" id="pn_input"/>页
  42. <input id="searchPageBtn" type="button" value="确定">
  43. </div>

价格搜索区间:
image.png

用户登录的信息保存在sessionScope域中

注销用户:
1 销毁session中的用户登录信息
2 重定向会首页或者登录页面

  1. //1 销毁session中的用户登录信息
  2. request.getSession().invalidate();
  3. //2 重定向会首页或者登录页面
  4. response.sendRedirect(request.getContextPath());

表单重复提交
表单重复提交有三种常见的情况:
1 提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键F5,就会发起最后一次的请求。造成表单重复提交问题
解决方法:使用重定向来进行跳转

2 用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候多点几次提交操作,也会造成表单重复提交
3 用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交
image.png

谷歌 kaptcha 图片验证码的使用

  1. //配置xml文件
  2. <servlet>
  3. <servlet-name>KaptchaServlet</servlet-name>
  4. <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
  5. </servlet>
  6. <servlet-mapping>
  7. <servlet-name>KaptchaServlet</servlet-name>
  8. <url-pattern>/Kaptcha.jpg</url-pattern>
  9. </servlet-mapping>
  10. //在表单中img标签去显示验证码并使用
  11. <img id="code_img" alt="" src="Kaptcha.jpg">
  12. #验证码的切换
  13. //给验证码的图片 绑定单击事件
  14. $(function (){
  15. $("#code_img").click(function (){
  16. //this 对象,表示当前正在响应事件的dom对象
  17. //src 属性表示验证码 img 标签的图片路径。它可读,可写
  18. this.src="${path}Kaptcha.jpg?d="+new Date();
  19. });
  20. });

购物车模块实现(使用session保存)
image.png

使用Filter过滤器实现后台的权限管理

  1. <filter>
  2. <filter-name>managerFilter</filter-name>
  3. <filter-class>com.book.filter.managerFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>managerFilter</filter-name>
  7. <url-pattern>/pages/manager/*</url-pattern>
  8. <url-pattern>/manager/bookServlet</url-pattern>
  9. </filter-mapping>

error 标签配置错误页面

  1. <error-page>
  2. <error-code>404</error-code>
  3. <location>/pages/error/error_404.jsp</location>
  4. </error-page>

注:再收到异常后,要继续把异常往外抛,tomcat服务器收到异常后就会处理相应的错误代码页面