JavaWeb核心
一、使用Servlet做一个单表的CRUD操作
第一步:创建数据库表
第二步:准备一套HTML页面中的链接,使业务都能跑通,实现页面流转
第三步:分析系统包括的功能(CRUD)
第四步:在IDEA中搭建环境
创建一个webapp,向webapp中添加连接数据库的jar包(放在WEB-INF目录下的lib包内),JDBC工具类
第五步:实现第一个功能:查看部门列表
- 从前端开始,从用户点击按钮开始
- 第一:将查看部门列表的超链接修改为请求路径名,请求路径以
/
开始,带上项目名<a href="/oa/dept/list">查看部门列表</a>
- 第二:编写web.xml文件
<servlet> <servlet-name>listDept</servlet-name> <servlet-class>com.mysite.oa.web.action.DeptListServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>listDept</servlet-name> <url-pattern>/dept/list</url-pattern> </servlet-mapping>
- 第三:编写DeptListServlet类继承HttpServlet类,重写doGet方法
- 第四:连接数据库,查询所有的部门,动态的展示部门列表页面
- 分析list.html页面中哪部分是固定的,哪部分是动态的
- 第五:实现第一个功能:查看部门列表
- 第六:查看部门详情功能:
- 建议:从前端往后端一步一步实现
- 技巧:将部门编号的信息放在地址栏,在detailDept 中获取地址栏的参数信息即可。这里不能在DeptListServlet 类中设置缓存(应用域或请求域)数据可能不是实时的。
out.print("<a href='"+contextPath+"/dept/detail?deptno="+deptno+"'>详情</a>"); //动态获取项目的根路径使用 String contextPath = request.getRequestContextPath();
- 第七:删除部门
- 在前端页面上写JS代码,来提示用户是否删除
删除
- 在前端页面上写JS代码,来提示用户是否删除
- 第八:新增部门
- 注意:最后保存成功之后,转发到/dept/list的时候,会出现405,为什么?
- 1.保存用的是post请求,底层要执行doPost方法
- 2.转发是一次请求,之前是post,之后还是post,因为它是一次请求
- 3.
/dept/list
Servlet当中只有一个doGet方法 - 解决方法
- (1)在/dept/list Servlet中添加doPost方法,然后再doPost方法中调用doGet
- (2)重定向
- 第九:跳转到修改部门的页面
- 第十:修改部门
- 第一:将查看部门列表的超链接修改为请求路径名,请求路径以
二、重定向与转发
在web应用中完成资源的跳转有两种方式 转发和重定向
- 转发:
//获取请求转发器对象,传入需要转发的Servlet路径,不带项目名 //转发的时候是一次请求,不管转发多少次,都是一次请求,都在同一个request域中 request.getRequestDispatcher("/dept/list").forward(request,response);
- 重定向
//注意路径上要加一个项目名 //这里是浏览器向服务器又发送了一个请求 所以 需要加项目名 response.sendRedirect("/oa/dept/list");
转发和重定向的区别:
- 转发(一次请求)
在浏览器地址栏上发送的请求是:http://localhost:8080/servlet09/a
,最终请求结束之后,浏览器地址栏上的地址不变。 - 重定向(两次请求)
在浏览器地址栏上发送的请求是:http:localhost:8080/servlet09/a
,最终在浏览器地址栏上显示的地址是:http:localhost:8080/servlet09/b
转发和重定向的本质区别?
- 转发:是由WEB服务器来控制的。A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
- 重定向:是由浏览器来完成的。具体跳转到哪个资源,是由重定向的位置(location)决定的
转发和重定向应该如何选择?
如果在上一个Servlet当中向request域中绑定了数据,希望从下个Servlet当中把request域里面的数据取出来,使用转发机制,剩下的所有请求均使用重定向。(重定向使用较多)
三、会话 (session)
会话(session)指用户打开浏览器,进行一系列操作,最终将浏览器关闭,这整个过程叫做一次会话。一次会话中可以包含多个请求。
由于Http协议是一种无状态协议,所以需要使用session 保存会话状态,
无状态指请求的时候,B和S 是连接的,但是请求结束之后,连接(通道)就断了。
为什么不使用request对象保存会话状态?为什么不使用ServletContext对象保存会话状态?
- ServletContext对象是服务器启动的时候创建的,服务器关闭的时候销毁,这个ServletContext对象只有一个
- request < session < application (请求域 < 会话域 < 应用域)
session 对象的实现原理:
- HttpSession session = request.getHttpSession();
- 从服务器中获取当前的session 对象
- 如果没有获取到任何session对象,则新建
- HttpSession session = request.getSession(false);
- 从服务器中获取当前session对象
- 如果获取不到session,则不会创建,返回一个null
session对象是由服务器创建的,存储在服务器端,Web服务器中有一个session集合,类似于map集合, key对应sessionid, value对应session对象。
session 的创建过程:
- 用户发送第一次请求:服务器会创建一个新的session对象,同时生成一个对应的 sessionid,服务器会将 sessionid 发送给浏览器,浏览器将 sessionid 保存在浏览器的缓存中。
- 用户发送第二次请求:会自动将浏览器缓存中的 sessionid 自动发送给服务器,服务器获取到的 sessionid,然后从 session 集合中找到对应的 session对象。
为什么关闭浏览器,会话就结束了?
- 关闭浏览器之后,浏览器缓存中保存的sessionid失效,下次重新打开浏览器之后,浏览器缓存中没有这个sessionid,自然找不到服务器中的session对象。session对象找不到等同于会话结束。
session对象什么时候销毁?
- 超时销毁
- 手动销毁
四、Cookie
session 的识别依赖于 Cookie,session 会将 session 对象对应的 sessionid 告诉 Cookie,比如 JSESSIONID=xxx
,Cookie 存储了当前 session对象的 sessionid。
Cookie 通常保存在浏览器的运行内存中的,只要浏览器不关闭,用户再次发送请求的时候,会给将运行内存中的 Cookie 一起发送给服务器,服务器是根据JSESSIONID对应的 sessionid 来找到对应的session对象。
Cookie 保存在浏览器上,可以保存在运行内存中。(浏览器关闭cookie就消失了),也可以保存在硬盘文件中(永久保存)。
cookie和session机制都是为了保存会话的状态,因为HTTP协议是无状态协议,所以需要使用session和cookie机制
如果Cookie禁用了,session还能找到吗?
- Cookie禁用后无法保存sessionid 到浏览器,不能找到对应的 session对象,每次请求都会创建新的 session对象
cookie禁用后,session机制还能实现吗?
- 可以。需要使用URL重写机制,把 session 信息拼接到 url 路径上,
如:http://localhost:8080/servlet11/test/session;jsessionid=7ECA8308439C94F9FC6301ACBBF210A
五、过滤器
在项目中每个Servlet执行之前都是需要判断用户是否登录了。判断用户是否登录的代码是固定的,需要在每一个Servlet类中都实现,代码过于冗余,复用性差。可以使用Servle规范中的Filter过滤器来解决。
Filter可以在Servlet这个目标程序执行之前添加代码。也可以在目标Servlet执行之后添加代码。之前之后都可以添加过滤规则。
自定义 Filter过程:
- 第一步:编写一个java类实现一个接口:javax.servlet.Filter。并且实现这个接口中的所有方法
- init方法:在Filter对象第一次被创建之后调用,并且只调用一次
- doFilter方法:只要用户发送一次请求,则执行一次。发送N次请求。则执行N次。在这个方法中编写过滤规则。
- destroy方法:在Filter方法被释放/销毁之前调用,并且只调用一次.
- 第二步:在web.xml文件中对Filter进行配置。
注意:
- Servlet对象默认情况下,在服务器启动的时候不会新建对象。
- Filter对象默认情况下,在服务器启动的时候会新建对象。
- Servlet是(伪)单例的。Filter也是单例的。(单实例)
Filter的生命周期和Servlet对象生命周期一致,唯一的区别就是在默认情况下,Filter在服务器启动时就实例化。
Filter过滤器的的实现体现了责任链设计模式。在程序编译阶段不会确定调用顺序,因为Filter的调用顺序是配置到web.xml文件中的。只要修改web.xml配置文件中filter-mapping的顺序就可以调整Filter的执行顺序。Filter的执行顺序是在程序运行阶段动态组合的。