C/S结构是客户端/服务器端(client/server)比如QQ,LOL
需要编写服务器端的程序,以及客户端的,我们安装的qq包就是客户端程序
缺点:软件更新时客户端与服务器端都要更新,服务器端更新时客户端无法使用,比较麻烦,你想要运行对应的客户端程序,硬件必须支持
优点:安全心比较高【一对一的关系】
B/S结构浏览器端/服务器端(Browser/server)
优点:只需要编写服务器端,不需要维护浏览器,不需要硬件支持只要一个浏览器
缺点:安全性比较差
Web资源【服务器资源 发布到服务器上的文件】
web资源的分类
1静态资源:html【浏览器可以直接查看】
2动态资源:jsp/servlet【需要先转换成html 再给游览器去渲染】
静态资源与动态资源的区别
如何来访问web资源的【如何逛淘宝】
打开浏览器:输入URL
URL:协议名://域名:端口/路径 如:http://www.baidu.com/one/123.html
【域名里就是对应的服务器的ip地址】
Web服务器的作用,就是接受客户端的请求,给客户端做出响应
对于javaweb程序而言还需要有jsp/servlet容器【不单单只是一个静态页面】
Jsp/servlet容器基本功能就是把我们动态页面转换成静态的
所以需要使用的是web服务器和jsp/servlet容器 下面接受几个常用的javaweb服务器
Tomcat(Apache) 当前应用最为广泛的javaWeb服务器【免费的】
【只能支持javaweb javaweb只是javaEE的一部分】
Jboos:支持javaEE,应用比较广泛【javaEE主要的部分是EJB容器 企业级容器】
GlassFish(oracle):javaweb服务器,应用不是很广
Resin:支持javaEE 应用越来越广
Weblogic(oracl):javaEE的服务器:【适合大型项目 要钱】
WebSohere:javaEE的服务器:【适合大型项目 要钱】
Tomcat服务器是由Apache提供的,开源/免费的,由于Sun和其他公司参与到了Tomcat的开发中。所以最新的jsp/servlet规范总能在tomcat中体现出来。
当前最新的是Tomcat9.0.1,
Tomcat7 支持servlet3.0
Tomcat6 支持 servlet2.5
【企业开发中是否选择最新版? 一般用低版本】
Tomcat的安装,启动,配置
下载:tomcat网站 http://tomcat.apache.org
Tomcat分为解压版和安装版
安装版:一台电脑只能安装一个tomcat
解压版:无须安装,解压就能用,随你解压多少次
Bin:存放的各种平台下的停止和启动tomcat的脚本文件
Conf:放置的tomcat服务器的各种配置文件
Lib:放置的是tomcat所需要的各种jar文件
Logs:放置的是tomcat运行时的日志文件
Temp:放置的是tomcat运行时 用于存放临时文件
Webapps:发布web应用时,默认情况下会将WEB文件放置在该目录下
Work:放置的是动态页面转换成静态页面的文件
【由jsp生成的servlet文件】
LICENSE 许可证
NOTICE 说明书
在启动tomcat时我们必须配置环境变量
1.java_home必须配置的 因为启动tomcat需要使用jdk
2.启动 点击startup.bat
3.关闭 点击shutdown.bat
为什么startup.bat就可以开启服务器? 执行步骤
startup.bat---catalina.bat---setclasspath.bat---java_home;
所以java_home必须配置的
启动不了黑框一闪而过:可以检查java_home是否配置
http://localhost:8080
打开conf/server.xml:
http:默认的端口号为80 也就是说在URL中不给端口号就表示使用80端口,当然你也可以进行修改
如果你把端口号修改为80 浏览器直接输入http://localhost 就可以直接进入服务器
静态网站:(漂亮的驱壳)
如何发布静态的网址:
1.在webapps下创建一个目录(命名不能有特殊字符和汉字)目录就是项目
2.在该目录下新建一个静态的页面【xxx.html】就可以了
动态网站:(注入灵魂)【可以使用变量的】
如何发布动态的网址
1.在webapps下创建一个目录(命名不能有特殊字符和汉字)目录就是项目
2.在项目文件夹下创建如下内容
2.1 WEB-INF目录在该目录下创建web.xml文件【去复制】
2.2创建动态页面XXX.jsp
完整的web应用还需要在web-inf目录下创建
Classes 【java编译的.class文件】
Lib 【项目所要使用的工具jar包】
Webapps
Projectname【好比--student】
WEB-INF
Web.xml
Classes
lib
Index.jsp【好比---lsd.jsp】
注意:wen-inf:这个目录必须大写,这个目录下的文件无法通过浏览器访问
Web.xml 应用程序的部署描述文件 可以在该文件中对应用进行配置
比如配置某一个页面为主页……….
协议:协议的甲方和乙方 客户端(浏览器)与服务器端
理解成双方的通信方式
1.请求协议
2.响应协议
HTTP(超文本传输协议)就是规定了浏览器与服务器之间的通信规则
规定了客户端发送给服务器端的内容格式 :请求协议
也规定了服务器端响应给客户端发的内容格式 :响应协议
什么是请求协议【请求协议的格式】
请求行
请求头 【键值对】
空行
请求体
Request 请求
GET/teacher/sd.html HTTP/1.1
Get请求请求服务器的路径是teacher/lsd.html协议为http1.1
Host:localhost:8080
请求的主机名为localhost端口号为8080
Connection:keep-alive
客户端支持的连接方式,保持一段时间的连接默认为3000MS
Cache-Control:max-age=0
在指定的时间访问同样的网页不去服务器直接访问
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 告诉服务器当前客户端可以接受的文档类型*/*
Upgrade-Insecure-Requests:1
第一次请求的意思
User-Agent: Mozilla/5.0 (Windows NT 5.1)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36
与浏览器相关的信息,有些网站会显示用户的系统和浏览器的版本,这些有User-Agent来获取的
Accept-Encoding:gzip, deflate, sdch
支持的压缩格式,数据在网络上传递时,可能服务器会把数据压缩之后在进行发送
Accept-Language:zh-CN,zh;q=0.8
当前客户端支持的语言
Accept-Charset:GB2312,utf-8
当前客户端支持的编码
Cookie
记录用户信息并保存在本地
什么是响应协议【响应协议的格式】
响应行
响应头 【键值对】
空行
响应体
HTTP/1.1 200 OK
响应协议为http1.1状态码为200表示请求成功 ok对应状态码的解释
Server:Apache-Coyote/1.1
服务器的版本信息
Accept-Ranges:bytes
响应体以字节传输
ETag:W/"261-1509694900406"
Last-Modified:Fri, 03 Nov 2017 07:41:40 GMT
在规定的时间接收相同的请求不会给客户端响应
Content-Type: text/html
响应体为文本
Content-Length:261
响应体的长度为261个字节
Date: Fri, 03 Nov2017 07:41:57 GMT
响应的时间,可能会有8个小时的时区查
200 请求成功 浏览器会把响应体(html)显示在浏览器
304 服务器端接收到相同的请求
302 重定向表示服务器要求浏览器重新发送请求
404 请求的资源未找到
500 请求的资源找到了,但是内部出现了错误
Servlet在浏览器中起到什么作用?
Servlet是javaweb的三大组件之一,它属于动态资源。
Servlet的作用就是处理请求,服务器会把接收到的请求交给对应的servlet处理!
在servlet中通常需要:
1.接收请求数据 【如果注册的情况就要得到 姓名/密码/身份证..】
2.处理请求 【接收数据封装对象 调用biz方法】
3.完成响应 【提示注册成功/失败了?】
如何实现servlet?【servlet是需要我们编写的】
实现servlet的三种方式
1.实现 javax.servlet.Servlet接口
2.继承 java.servlet.GenericServlet类 实现Servlet
3.继承 java.servlet.http.HttpServlet 类 继承GenericServlet
实现servlet接口实现loginServlet
1.问题 如何通过浏览器来访问 servlet【类】?
明确浏览器的URL 只是一个地址
能通过映射来实现,如何映射?如下↓问题:之前咱们如何执行一个类的方法?
1.实例化类 2.通过对象调用类的方法
虽然servlet类是我们编写的,但是servlet中的大部分方法不由我们来调用,而是由服务器(TomCat)来调用,并且servlet的对象也不由我们创建,而是由服务器创建,而且一个servlet类型,服务器只创建一个实例对象,线程不安全,效率快。
实例化:服务器会在servlet第一次被访问的时候创建servlet
初始化:调用init方法
处理请求:当服务器每次接收请求时,都会去调用service处理
销毁:在服务武器关闭时,服务器会销毁servlet调用destroy()
getServletConfig()
servlet容器在初始化期间将信息传递给servlet的servlet配置对象【ServletConfig】
ServletConfig对象的作用?【读取servlet的配置文件 刚刚的映射我们去读了么?】
ServletConfig对象是由服务器创建的,然后传递给servlet的init()方法
可以再init方法中使用
String getServletName() 获取servlet在web.xml中配置的名称,
就是
也就是说:一个servlet对象,对应一段web.xml中的servlet配置信息】
getInitParameter(Stringname) 用来获取web.xml里配置的初始化参
数值,更具名字来获取的。
getInitParameterNames() 用来获取在web.xml里配置的初始化参的
名称总合。
getServletContext() 获取ServletContext对象 后面单独说
-----------------------------------
ServletRequest和 ServletResponse
一个是请求对象,一个是响应对象,可以从ServletRequest对象中获
取请求的信息,可以从ServletResponse对象中完成响应,他们两都
成双成对的出现的
继承HttpServlet 实现查询功能的servlet
接收请求为什么
service(HttpServletRequestarg0, HttpServletResponse arg1)
也是可以的。
在httpServlet的
service(HttpServletRequest request,HttpServletResponse response)
方法会判断当前的请求到低是get/post,如果是get请求,那么会
去调用get请求,如果是…..。这说明我们以后真真编写的代码因该在
哪里? 以后只会重写doGet()和doPost()就行了。
因为一个类型的servlet只有一个实例对象,那么就有可能出现servlet同时被多个人请求,那么servlet就会存在线程安全问题。
所有我们不应该在servlet中创建全局变量,一般都是局部变量
因为可能会存在一个线程对这个成员变量进行操作,另一个线程对这个成员变量进行读取
一般的大佬行为:创建有状态的成员,该状态为只读
默认情况下,服务器会在某个servlet第一次收到请求的时候创建,也可以在web.xml中对servlet进行配置,使服务器在启动的时候创建servlet。
如何在web.xml中配置
在
问题:多个
<servlet-mapping>
<servlet-name>ReServletservlet-name>
<url-pattern>/address1url-pattern>
<url-pattern>/address2url-pattern>
servlet-mapping>
两个址都可以访问
路径匹配
如:/user/add.jsp /user/servlce/update
扩展名匹配
如:/lsd.jsp /123/456/789/lsd.jsp
匹配所有
获取的只是一个字符串,凭什么能调用里面的方法?
Classcl=Class.forName(“cn.niit.web.ReServlet”);//创建class对象
ReServletrs=cl.newinstance();//调用无参构造创建对象
Method me=cl.getMethod(“service”,ServletRequest.class,
ServletResponse.class); //找到调用的方法
me.invoke(rs,servletRequest,servletResponse);//方法的调用
一个项目只有一个servletContext对象!
我们可以在N多个servlet中来获取这个惟一的对象,使用它可以给多个servlet传递数据【有的时候称为上下文】
与服务器同生共死的。这个对象在tomcat启动时创建,关闭时销毁
Servlet概述
服务器会为每个应用创建一个servletContext对象
如何获取ServletContext对象?
1.Servlet getServletContext();
ServletContext sc=cfg.getServletContext();
2.Generic getServletContext();
ServletContext sc=this.getServletContext();
两个指的是同一个对象
ServletContext是javaweb的四大域对象之一
1.pageContext
2.servletRequest
3.HttpSession
4.ServletContext
所有的域对象都是用来存取的这么一个功能
因为域对象的内部都有一个Map用来存储数据,下面接受存取的方法
Void setAttribute(String name,Object value)用来存储一个对象,也称之为存储一个上下文域属性。
如果咱们setAttributer里的String name值设了相同键 那么会覆盖上面一个值。
如:setAttributer(“sd”,”tian”)
setAttributer(“sd”,”tian”) 取得是这个
Object getAttribute(Stringname)用来获取ServletContext中对应name名字的value值,如果没有这个键返回null;
RemoveAttribute(String name)用来移出ServletContext中对应name名字的键值对。如果键不存在,啥都不做。
Enumeration getAttributeNames() 获取说要域属性的name值(获取存的键)
统计浏览器的访问人数?
获取应用的初始化参数
Servlet也可以获取初始化参数信息,但是它是局部的,也就是说,一个servlet只能获取自己的初始化参数。
那我们现在想配置一个全局的初始化参数,让所有的servlet共享
如何来配置? 在web.xml下
如何在servlet里获取配置的全局信息
//读取全局的配置信息
请求的响应的流程?
服务器处理请求的流程:
1服务器每次接收到请求,、都会为这个请求开辟一个新的线程
2服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体。
3服务器还会常见response对象,与客户端连接在一起,他可以用来给客户端发送响应
Response是servlet方法的一个参数,类型为javax.servlet.http.httpServletResponse,客户端发出每次请求,服务器都会创建一个response对象【登录与注册的响应结果是相同的吗?】
并传入service()中。Response对象是用来对客户端进行响应的,说明在service()中使用response对象可以完成对客户端的响应工作。
回忆之前的http的协议
状态码
一堆响应头信息如:Context-type:texe/html;Charset=utf-8
区分不同的数据其相应的编码为utf-8
空行
响应正文【……….】
Response对象的功能分为以下四种?
1.发送状态码
2.设置响应头信息
3.设置响应的正文
4.重定向
设置状态码:
setStatus(int sc) 发送成功的状态码,可以用来发送200/302
sendError(int sc) 发送错误的状态码 如404,500
sendError(int sc,Stringmessage) 发送错误的状态码,附带错误信息
设置响应头/自定义响应头
可以使用response对象的setHrader()方法来设置响应头,使用该方法设置的响应头会发送给客户端浏览器。
Context-type:texe/html;Charset=utf-8
response.setHeader(“Context-type”,”Charset=utf-8”) 设置context-type响应头,该头的作用是,告诉浏览器响应的内容是html类型编码为utf-8,而且会设置response的字符编码为utf-8
response内部有一个方法来简化响应的编码
response.setCharacterEncoding("utf-8")
5秒后跳转对应的servlet/网站
response.serHeader(“ReFersh”,”5,http://www.baidu.com”);
response.serHeaderr(“ReFersh”,”5,/2017-11-7/servletA”);
禁止缓存 【有好有坏】 各个版本的使用
response.setHeader(“Cache-Control”,”no-Cache”);
response.setHeader(“pragma”,”no-Cache”);
response.setDateHeader(“expires”,-1);
适用于单值的响应头
response.setHeader(String name,String value);
适用于多值的响应头
addHeader(Stringname, String value)
addHeader(Stringname, String value)
如
response.addHeader("ld","东");
response.addHeader("ld","西");
适用单个值的int类型的响应头
response.setIntHeader(Stringname,int value);
如:response.setIntHeader(“Content-Length”,888);
适用多个值的int类型的响应头
addIntHeader(Strignname,int value)
适用单个值的毫秒类型的响应头
response.setDateHeader(Stringname,long value);
适用多个值的毫秒类型的响应头
response.addDateHeader(Stringname,long value);
什么是重定向
当你访问http://www.sun.com时,你会发现浏览器地址栏的url发生了改变,这就是重定向。
重定向就是服务器通知浏览器去访问另外一个地址。即再发送一个请求。
通过代码实现重定项
1.响应码为200表示响应成功,而响应码为302表示重定项,
所以第一步设置响应码为302
2. 因为重定项是通知浏览器再一次发送请求,所以浏览器需要知道第二次请求的URL,所以完成重定向第二步设置请求的URL
便捷的重定向---以后我们就是这么写的
response.sendRedirect(Stringurl)
重定向小结
1.重定向是两次或多次请求
2.重定向的URL可以是其他的应用,不一定局限于当前应用
3.重定向的响应头是302,并且必须要有Location响应头
response响应正文
response是响应对象,向客户端输出响应正文,可以使用response的响应流,response一共就提供了两个响应流
如果响应的正文是字符,那么使用getWriter(),
如果响应的内容为字节如下载,使用getOutputStream();
注意点:在一个请求中,不能同时使用这两个流。
字符响应编码
在使用getWriter()时默认的编码为ISO-8859-1,如果不希望出现乱码就设置字符流编码为utf-8;
可以使用response.setCharaceterEncoding(“utf-8”);可以保证输出给客户端的字符为utf-8。
如果希望通知客户端使用utf8来解读响应的数据那
就需要使用response.setContentType("text/html;Charset=utf-8");
因为这个方法不止会调用setCharaceterEncoding
还会设置响应头 content-type 【告诉浏览器拿u8来读取响应体】
缓冲区
和之前的打印流一样
request是service方法的一个参数,类型为javax.servlet.http.HttpServletRequest.
在客户端发出的每个请求,服务器都会创建一个request对象
并把请求的数据封装到request对象中,然后调用service传递过去
说明在service方法中request对象可以读取请求的所有数据
回顾一下请求协议
请求行
请求头
空行
请求体(get没有请求体)
Request的功能可以分为一下几种
1.封装了请求头数据
2.封装了请求体数据,如果是get请求没有请求体【正文】
3.request是一个域对象,可以把它当做一个Map集合
4.request提供了请求的转发和请求的包含功能
request获取请求头数据的方法有:
request获取请求相关的其他方法
案例封IP
Request获取请求的参数
最长见的客户端传递参数有 两种方式
1.浏览器地址栏输入网址,一定是get请求
2.超链接,一定是get请求
3.表单:可以是get请求也可以是Post请求 有method决定
get请求
1.请求的参数会在浏览器的地址栏中显示,所以不安全
2.请求的参数长度有限制
3.get请求无请求体,无法通过setCharacterEncoding()来设置参数编码
Post请求
1.请求的参数不会在浏览器的地址栏中显示,相对安全
2.请求参数长度没有限制
使用request的什么方法获取请求值
String request.getParameter(String name);通过指定的名称获取参数值
String [] request.getParameterValues(String name);方多个参数名相同时可以指定名称获取多个参数值
Enumeration request.getParameterNames();获取所有参数的名字
Map request.getParameterMap(); //获取所有参数封装到Map中,其中key为参数名,value为参数值, 因为一个参数名可能对应多个值,所以参数的值是String[],而不是string 【map
请求转发和请求包含
如何实现请求转发
requestDispatcher rd= request.getRequestDispatcher("/servletB");
rd.forward(request,response);
如何实现请求包含
requestDispatcher rd= request.getRequestDispatcher("/servletB");
rd.include(request,response);
请求转发和请求包含的差别
如果servletA中请求转发到servletB,那么在servletA中就不允许出现输出响应体。如果使用请求包含那么就没有这个限制
请求转发虽然不能输出响应体,但是可以设置响应头如:
response.setContentType("text/html;charSet=utf-8");
什么时候使用转发/包含
请求包含大多是应用在jsp页面中,完成多个页面的合并
请求转发大多是用在servlet中。转发的目标大多是jsp页面
转发和重定向的差别
相同点:都可以用来跳转servlet和页面
不同点
你想跳转不论是servlet和页面只要你想传数据你就用转发
你如果你想跳转不论是servlet和页面不带数据你就用重定向
响应编码:response.setCharaceterEncoding(“utf-8”)
保证了输出给客户端的响应体的编码格式是utf-8,但是浏览器不知道
response.setContextType(“text/html;charSet=utf-8”)
内部即调用了setCharaceterEncoding方法而且设置了ContextType响应头告诉浏览器以响应头对应的编码来解读
请求编码:request.setCharacterEncoding(“utf-8”)设置请求体的编码格式,因为只有post请求才有请求体,所有该编码只对post请求的数据有效。
如何设置get请求的编码
两种方法
治标
String name=request.getParameter("name");
String newname=newString(name.getBytes("iso-8859-1"),"utf-8");
治本
在conf/server.xml
开发个选哪一个? 治标
路径
转发和包含的路径以”/”开头相当于:http://locaolhost:8080/项目名/
重定向以”/”开头相当于 :http://locaolhost:8080/
request作用域
request是域对象,在javaweb中一共有4个域对象,request可以再一个请求中共项数据
一个请求会创建一个request对象,如果在一个请求中经历了多个servlet,那么多个servlet就可以使用request来共享数据。
request的域方法
setAttribute(String name,Object obj);存储一个对象,也称之为域属性
如果使用相同的name,那么会覆盖之前那个nam对应的键值
getAttributer(String name);
removeAttribute(String name);
Enumeration getAttributeNames();获取所有域属性的名称
Jsp(java server pages)是javaweb服务器端的动态资源,他与html的作用是相同的,显示数据和获取数据的【jsp可以通过变量来显示数据】
Servlet:
缺点:不适合设置html的响应体,因为需要大量的
response.getWriter().print(“”);
优点:动态资源,可以编程。
Html:
缺点:html是一个静态的页面,不能包含动态资源
优点:可以不用输出标签,标签可以直接写。
Jsp:
优点:在原来的html基础上添加java脚本,构成jsp页面。
Jsp和servlet的分工
Jsp:作为请求的发起页面。例如:表单的提交,超链接的点击
作为请求的结束页面。显示登录的结果,显示访问的网址
Servlet:作为请求处理数据的环节
1.jsp=html+java脚本(java代码块)+jsp动态标签
2.jsp中有无须创建就可以使用的9大内置对象,如:request,response
3. 3中java脚本
<%....%>:java代码块,可以在里面定义0-N条java语句
Java方法里面咋写,你这里就咋写
<%=…..%>:java表达式,用于输出表达式或变量的结果
System.out.print() 括号里写啥,你这就写啥
<%!....%>:声明,用来创建类的成员变量和成员方法(基本不用,但是面试可能会被问到。。。)
Java类中你写啥,这里就可以写啥、
案例:明确jsp与servlet的分工
Jsp是特殊的servlet
Jsp是特殊的servlet,当jsp页面第一次被访问的时候,tomcat会把jsp翻译成.java文件,然后再把java文件编译成.class文件,然后由服务器去创建class对象,最后调用_jspService(request response)
Servlet的创建:第一次接受请求服务器创建servlet对象,且同一类型的servlet只会创建一次。调用service方法(request response)
<%-- --%>不会被编译
Html的注释
不会再浏览器上显示,但是可以查看
【为什么再次登录的时候 用户名框会有你之前输入的账号
预览商品,为什么会有,你访问过得商品】
1.Cookie是HTTP协议的规范之一,它是服务器端和客户端之间传输的小数据。
首先是由服务器通过响应头把Cookie传输给客户端。
response.addHeader(“Set-Cookie”,”lsd-lsdd”);
response.addHeader(“Set-Cookie”,”lsx-lsxx”);
客户端会将Cookie保存起来
2.当客户端再次【不管是否从新打开浏览器】请求同一个服务器,客户端会在请求头中添加服务器保存在客户端的cookie。
让服务知道 你就是刚刚访问我的那个人
Cookie的规范(保证浏览器的压力)
Cookie通过请求头和响应头在服务器和浏览器之间传输。
Cookie的大小限制在4K之内
一台服务器在一个客户端做多只能保存20个cookie
【百度只能在谷歌保存20个cookie……..】
一个浏览器最多可以保存300个Cookie;
【谷歌浏览器可以保存来自于不同服务器的 总共300个】
虽然Cookie规范是如此,但是浏览器之间的竞争不允许。所以都会超出规范限制,但是也不会超出太多。
JavaWeb中使用Cookie
原始的方式:
使用:response发送Set-Cookie的响应头给浏览器
使用:request获取Cookie的请求头
便捷的方法
使用:response.addCookie(Cookie cookie); 向浏览器保存Cookie
使用:request.getCookie(); 获取浏览器归还的Cookie
案例:a.jsp保存了Cookie,b.jsp归还Cookie
Cookie的细节
Cookie的MaxAge
当服务器创建cookie对象后,可以调用setMaxAge方法来设置Cookie的最大生命。默认浏览器关闭就死掉。
MaxAge>0 表示cookie在客户端硬盘上的保存的最大时间 单位S
MaxAge<0 表示默认浏览器关闭就死掉
MaxAge==0 表示删除cookie
【通过谷歌查看Cookie的生命 设置-内容设置-Cookie—查看Cookie】
在javaweb中提供Httpsession类,用于表示http会话
会话可以理解为客户端与服务器端的一次交流
获取Httpsession的对象
HttpSession session= reqeust.getSession();如果当前会话已经有了session对象,那么直接返回,如果当前会话不存在,创建并返回。
HttpSession session= reqeust.getSession(boolean); 如果参数为true与不写一样,如果为false返回已存在的session,没有返回空。
HttpSession是域对象
我们已经学了HttpServletRequest,ServletContext,
HttpServletRequest,ServletContext,httpSession是servlet的域对象
HttpServletRequest:一个请求创建一个reqeust对象,所有在同一个请求中共性reqeust。例如servletA转发到servletB,那么AB可以共享request域中的数据。只要不从新发请求
ServletContext;一个应用【项目】只创建一个servletContext对象,所以在servletContext中的数据可以再整个项目中共享。只有关闭服务器。
HttpSession:一个会话创建一个HttpSession对象,同一个对话中的多个请求和响应共享session中的数据。只要不管浏览器。
案例:login.jsp index1.jsp index2.jsp
先访问index1.jsp如果没登录的情况下,自动跳转login.jsp
Index2.jsp也是如此,如果发现登录了,显示欢迎XXX
SetAtributer(String name ,Object value);
getAttributer(String name);
removeAttributer(String name);
getAttributerNames();
Session其他的常用方法:
String getId(); 获取sessionid
Int getMaxInactiveInterval() 返回session的最大不在活动时间的时间。
setMaxInactiveInterval(int s) 设置session不在活动时间的最大时间。
Long getCreationTime() 返回session的创建时间
Long getLastAccessedTime() 返回session最后一次的活动时间
Vaoid Invalidate(); 让session失效
Boolean isNew() 判断该session是否是新的
还可以在web.xml 里设置session的时长
Jsp的标签指令格式:<%@指令名 attr1=”” attr2=”” ..... %>
一般都会把jsp指令放在jsp文件的最上方。但这不是必须的。一个页面可以有0-N个指令
Page指令是最为常用的指令,属性最多的指令。
Page指令没有必须的属性,例如:<%@page %>
Jsp页面中,任何指令都是可以重复出现的
如:<%@page import=”java.util.*” pageEncoding=”utf-8” %>
<%@page import=”cn.po.student”%>
<%@page import="java.util.Date,java.util.List"%>
Pag指令的属性pageEncoding和contentType
pageEncoding:它指定当前页面的编码格式,只要不说慌就不会出现乱码。
在服务器把jsp翻译成.java文件的时候使用pageEncoding。
ContextType:表示添加了一个响应头,等同于
:response.setContentType(“text/html;charset=utf-8”);
【为什么没有写这个属性呢】
当设置pageEncoding而没有设置contentType,contentType和pageEncoding相同;
当设置contentType而没有设置pageEncoding,pageEncoding和contentType相同;
也就是说设置了一个另一个相当于也设置了同的编码。如果都没设置全都是
ISO-8859-1
Page指令的import属性
导包的,可以使用多次,
<%@page import=”cn.po.student”%>
<%@page import=”cn.po.teacher”%>
也可以连写;
<%@page import=”cn.po.teacher,cn.po.student”%>
Page指令的errorPage和isErrorPage
errorPage:当前页面如果抛出异常,那么转发到那个页面。由errorPage来指定错误页。【errorPage=“b.jsp” 】
isErrorPage:指定当前的页面是否是错误页面。【通过我们的观察页面的状态码变成500】 这个页面出现了错误,只有这个状态码为500的错误页面才能使用
exception对象
web.xml里配置错误页面
在上例中: 当出现404时,会跳转到error404.jsp页面
当出现RuntimeExeception时,会跳转到errorRuntime.jsp页面
当出现非RuntimeExeception时,会跳转到error500.jsp页面
Page指令的autoFlush和buffer
autoFlush: 指定jsp的输出缓冲区满时,是否会自动刷新!默认为true,如果为false,那么在缓冲区满时抛出异常。
Buffer:指定缓冲区的大小,默认为8KB,通常不做修改
这两个属性一般我们不会去特意的设置,都是使用默认值。
Page指令的isELlgnored
表示是否忽略EL表达式。默认为false[支持使用EL表达式]
基本不怎么用的page指令
Language:指定当前jsp编译后的语言,默认为java
Info:jsp说明信息。
isThreadSafe:当前的jsp页面是否支持并发访问。默认false,true不能并发
session:当前jsp页面是否支持session 如果为false那么就无法使用session
extends:让jsp生成的Servlet去继承某个类
与request.Dispatcher的include()方法相似
request.Dispatcher的include()方法。包含和被包含是两个servlet,也就是两个.class。只是把响应的内容输出到页面。
<%@include%>在jsp被编译成java时,合并成一个java文件,然后在生成class
作用:把页面分解,使用包含的方式合并在一起,这样一个页面中不变的部分就是一个独立的jsp.而我们只要处理变化的页面
两个属性:
Prefix:指定标签库在本页面中的前缀,有我们自己取名字
Uri:指定标签库的位置
<%@ taglib prefix=“s” uri=”/struts-tags” %>
前缀的用法
在jsp中无需创建可以使用的9个对象它们是:
Out(jspWriter):等同于response.getWriter();向客户端发送响应体
Config(ServletConfig):等同于servlet中ServletConfig。获取该servlet在web.xml中对应的servlet节点的信息。
Page(就是当前jsp的类型):当前jsp页面的this,即当前对象。
pageContext(PageContext);页面的上下文,也是jsp的最后一个域对象
exception(Throwable);只有错误页面中可以使用该对象
request(HttpservletReqeust):即HttpServletReqeust类的对象
response(Httpservletresponse):即HttpServletresponse类的对象
session(HttpSession):即HttpSession类的对象,
【是不是每个页面都可以使用session?……..】
application(ServletContext):即ServletContext类的对象
在9大内置对象中极少用到:config,page,exception
在9大内置对象中不是每个jsp页面都可以使用的对象:exception,session
在9大内置我们学过的:out,request,response,application,session,config
pageContext:
Servlet中有三大域,而jsp中有四大域,它就是最后一个
Servlet | jsp | 作用范围 |
ServletContext | application | 整个应用程序 |
HttpSession | sesison | 整个会话(一个浏览器-一个服务器) |
HttpServletReqeust | request | 一个请求链 |
PageContext | 一个jsp页面 |
1.域对象
2.获取其他8个内置对象。【你看帮助文档】
3.代理其他域
pagecontext.getattribute(“..”,【pagecontext.application_ scope】);
4.全域查找:pageContext.findAttribute("name")从小到大一次查找
5.一顶9
这些jsp动作标签与html提供的标签有本质的区别 【html是由浏览器执行的】
动作标签是由tomcat[服务器]执行的,他与java代码一样,都是在服务器端执行。
【<%@include%>和
a.jsp
b.jsp
配置的补充
1.改了内部文件不重启服务 照样可以
Conf/Context.xml
Tomcat内部会每隔一段时间自动刷新,仅限开发使用
有的时候会失常【离下一次刷新的时间还没到】
2.为什么一个请求一个jsp页面服务器不会当成servlet?
当它确认是jsp后怎么去翻译成Java文件的?
JavaBean的规范;
1.必须要有一个默认的构造器
2.提供了get/set方法,如果只要get,那么这个属性是只读属性
3.属性:有get/set方法的成员,或者只有get/set方法
4.方法的名称满足一定的规范,那么他就是属性。Boolean类型的属性,他的读取方法可以is/get
内省
内省类--》Bean属性--》属性描述器--》属性的get/set对应的method—》反射
Jsp中与javaBean的相关标签【model1模型常用的标签 】
1.EL是jsp内置的表达式语言
Jsp2.0开始的,不让在使用java脚本,,而是使用EL表达式和动态标签来代替java脚本。
EL代替的是<%= %> 也就是说EL只能做输出。
2.EL表达式来读取四大域
${域的属性名} 全域搜索 如果不存在输出“”,而不是null
指定域获取属性
${pageScope.域的属性名},${requestScope.域的属性名}
${sessionScope.域的属性名},${applicationScope.域的属性名}
EL表达式的格式
1.读取list和数组:${list[0]},${arr[0]}
2.读取bean: stu对象 ${stu.name},${stu[‘name’]} 对应stu.getName()
3.读取Map:${map.key}.${map[‘key’]} 对应的是map.get(String key);
其实是调用自己的get方法来获取的值。
EL内置对象
EL一共有11个内置对象,无须创建直接使用,这11个内置对象10个是Map类型,pageContext类型
1.pageScope
2.requestScope
3.sessionScope
4.applicationScope
//这个两个参数专门用来读取请求的参数
5.param
Map
等同于:request.getParameter()方法相同
6.paramValues:
Map
当一个参数对应多个值的时候。
等同于:request.getParameterValues()方法相同
7.header:
他也是一个Map其中key表示头名称,value表示单个头值。
8.headerValues:
他也是一个Map其中key表示头名称,value是多个值
9.initParam 【全域的初始化参数】
10.Cookie
他也是一个Map其中key表示Cookie的名字,value表示Cookie对象
11.PageContext
可以使用pagecontet对象调用getXXX()方法,
如:pageContext.getRequest();
${PageContext.request}
EL表达式 说明
${pageContext.request.requestURL} PageContext.getReqeust().getRequestURL()
${pageContext.reqeust.contextPath} pageContext.getRequest().getContextPath()
${pageContext.request.method} pageContext.getRequest().getMethod();
${pageContext.session.new} pageContext.getSession().getisNew()
${pageContext.session.id} pageContext.getSession().getId();
以后action a location.href 必须使用${pageContext.reqeust.contextPath}
EL函数库
什么是EL函数库
EL函数库是由第三方提供的,对EL的扩展,我们现在学习的是JSTL提供的
EL函数库就是定义一些有返回值的静态方法,通过EL语言来调用。
导入函数库
因为是第三方提供的,所需要导包,jsp到标签库 taglib指令
<%@ taglib prefix="fn"uri="http://java.sun.com/jsp/jstl/functions"%>
EL函数库的介绍
String toUpperCase(String str);
String toLowerCase(String str);
Int indexOf(String str,String str2)
Boolean contains(Stringstr,String str2)
Boolean containsIgnore(Stringstr,String str2)
Boolean startsWith(String str,String str2)
Boolean endsWith(String str,String str2)
String subString(String str,int index1,int index2)
String subStringAfter(String str,String str2)
String subStringBefore(String str,String str2)
String escapeXml(String inoput)
String trim(String str)
String replace(String str,String strBefore,String StrAfter)
String[] split(Stringstr,String str2)
Int length(Object obj)
String join(String array[],String str)
自定义函数库
1.写一个类,写一个有返回值的静态方法
2./WEB-INF目录下建立文件夹tlds,在里面建立文件niit.tld文件【头文件可以复制】
3.在页面添加taglib指令导入标签库 ,使用 ${XX:XXX()}
什么是JSTL
JSTL是Apache对EL表达式的扩展,(也就是说JSTL依赖于EL),JSTL是标签语言。标签语言需要导入标签库。
JSTL标签库
JSTL一共有4打标签库
1.core:核心标签库,也是学习的中点
2.fmt:格式化标签库。我们只介绍两个(时间格式/数值格式)
3.sql:数据库标签,过时了
4.xml:xml标签库,过时了
使用taglib指令导入标签库
除了jsp的动作标签之外,使用其他的第三方标签库,都需要导库
<%@ taglib prefix=”c” uri=”http://java.sun.com/jsp/jstl/core “%>
Prefix=”c” 指定标签库的前缀,前缀一般使用c,所有有的人喜欢叫c标签
Uri:标签库指定的路径
常用的标签:
1.
Value:可以是字符串,可以是EL表达式
Default:当前输出的内容是null,会输出default指定的值
Escapexml:默认值为true,表示转义。
2.
Var:变量名
Value:变量的值,可以是EL表达式
Scope:变量存放的域,默认为page,可选page,request,session,application
3.
Var:你要删除的域属性名
Scope:如果不给Scope,表示删除所有域中的该名称变量
如果指定了域,只删除该域的变量
4.
如:
子标签:
如:
输出 /项目名/indexjsp?name=lsd
Var:指定变量,一旦添加这个属性,那么url标签就不会输出,而是把生成的url保存到域中。
Scope:他与var一起使用,用来指定保存url的域
5.
test :当test的值为true时,执行标签的内容;
6.:choose 类似if else if else if else
7.forEach:循环遍历
1.它可以用计数的方式循环!
Var:循环的变量
Begin:设置循环变量从几开始
End:设置循环变量到几结束
Step:设置步长 如step=”2”等于Java中的 i+=2
2用来遍历数组或集合
Items:指定要循环的集合或数组
Var:把数字或集合中的每一个元素赋值给var指定的变量
3.循环的状态
${vs.count} 获取当前循环的个数
${vs.index} 获取当前循环的下标
${vs.first} 当前元素是否为第一个元素 ${vs.last}当前元素是否为最后一元素
${vs.current} 获取当前循环的对象。
Fmt库 它是一个格式化标签库
日期格式化:
Value:指定一个Date类型的变量
Pattern:输出的格式!
数字格式化:
Value:指定一个数值类型的变量
Pattern:输出的格式0.00或#.## 他们都可以四舍五入,但是#.##在位数不足的情况下不能自动补0;0.00就可以。
MVC设计模式是所有的B/S项目的设计模式。把软件分成三个基本的部分
模型(Model) 视图(View) 控制器(controller)
可以对后期的维护/扩展起提供了方便。
控制器(controller)接收用户的请求,调用对应的方法,得到处理额结果,跳转对应的页面 (servlet)
模型(Model) 编写的javaBean实现增删改查 (JDBC)
视图(View) 呈现数据(jsp)
控制器接收请求调用模型处理,根据处理的结果调用不同的视图来呈现给用户
JavaWEB与MVC
经历了JspModel1一代,jspModel1二代,jspModel2三代
jspModel1第一代
最早的模型:适合小型的文本项目,开发成本极低,服务器端只有jsp页面,所有的操作都在jsp页面中执行。连数据库的访问也是在页面中编写的。也就是说,所有的东西全部耦合在了一起。对以后的维护/扩展极为不利
JspModel1第二代
JspModel1的升级版本,把业务逻辑放到了javaBean中,而jsp页面负责显示,以及请求的调度,虽然第二代比第一代好,但是jsp做了过多的工作。Jsp中把视图和控制器的事耦合在了一起
JspModel2第三代
已经清楚的看得见MVC的设计模式了
Jsp:视图层;用来和用户打交道,负责接收用户的数据以及显示给用户的数据
Servlet:控制层;负责找到合适的模型对象来处理业务逻辑,跳转到合适的视图
JavaBean:模型层 完成具体的业务工作
Java经典的三层架构
它是由Javaweb提出的。
所谓的三层!
业务逻辑层(Business Logic) biz
数据访问层(Data Access ) dao
WEB层 包含jsp,servlet,等与Web相关的内容
javaWeb的三大组件
1.servlet
2.Listener
3.Filter
监听器:
1.它是一个接口,内容由我们来实现
2.他需要绑定在一个特定的事件源上。
3.监听器中的方法,会在特殊事件发生时被调用。
现实举例:
事件源
杨志超
事件
玩手机
监听器
老师
监听器中的方法:打一顿/骂一顿 可以有多个方法。
javaWeb中的监听器【8个监听器】
事件源:在javaWeb中指三大域
ServletContext
生命周期监听:ServletContextListener,他有两个方法:一个在出生时调用,一个死亡时调用。
VoidcontextInitialized(ServlerContextEvent even); //创建servletContext时调用
VoidcontextDestoryed(ServlerContextEvent even); //销毁servletContext时调用
属性监听:ServletContextAttributeListener,他有三个方法:一个在添加属性时调用,一个在替换属性时调用,一个在删除属性时调用。
VoidattributeAdded(ServletContextAttributeEvent arg0) //添加属性时调用
VoidattributeReplaced(ServletContextAttributeEvent arg0) //替换属性时调用
Void attributeRemoved(ServletContextAttributeEventarg0) //移出属性时调用
HttpSession
生命周期监听:HttpSessionListener,他有两个方法:一个在出生时调用,一个死亡时调用。
VoidsessionCreated(HttpSessionEvent even); //创建HttpSession时调用
VoidsessionDestoryed(HttpSessionEvent even); //销毁HttpSession时调用
属性监听:ServletContextAttributeListener,他有三个方法:一个在添加属性时调用,一个在替换属性时调用,一个在删除属性时调用。
VoidattributeAdded(HttpSessionBindingEvent arg0) //添加属性时调用
VoidattributeReplaced(HttpSessionBindingEvent arg0) //替换属性时调用
VoidattributeRemoved(HttpSessionBindingEvent arg0) //移出属性时调用
HttpRequest
生命周期监听:ServletRequestListener,他有两个方法:一个在出生时调用,一个死亡时调用。
VoidrequestInitialized(ServlerRequestEvent even); //创建Request时调用
VoidrequestDestoryed(ServlerRequestEvent even); //销毁Request时调用
属性监听:ServletRequestAttributeListener,他有三个方法:一个在添加属性时调用,一个在替换属性时调用,一个在删除属性时调用。
VoidattributeAdded(ServlerRequestAttributeEvent arg0) //添加属性时调用
VoidattributeReplaced(ServlerRequestAttributeEvent arg0) //替换属性时调用
VoidattributeRemoved(ServlerRequestAttributeEvent arg0) //移出属性时调用
JavaWeb中完成编写监听器
1.编写一个监听器类实现某一个监听接口
2.绑定,与事件源进行绑定 [在web.xml中进行配置]
【以servletContext为事件源进行生死监听测试】
public class ServletContextLin implements ServletContextListener { //死之前 //把这些配置的数据清空/还原 public void contextDestroyed(ServletContextEvent arg0) { System.out.println("啊啊啊--- 要圆寂了....."); } //生之后 //用于服务器初始刷时,加载一些配置数据 public void contextInitialized(ServletContextEvent arg0) { System.out.println("耶耶耶 出生了............"); } } |
【以servletContext为事件源进行属性监听测试】
public class ServletContextAttr implements ServletContextAttributeListener { //添加属性时调用 public void attributeAdded(ServletContextAttributeEvent arg0) { System.out.println("添加属性"+arg0.getName()+"--->"+arg0.getValue()); } //删除属性时调用 public void attributeRemoved(ServletContextAttributeEvent arg0) { System.out.println("删除属性"+arg0.getName()+"--->"+arg0.getValue()); } //替换属性时调用 public void attributeReplaced(ServletContextAttributeEvent arg0) { System.out.println("替换属性"+arg0.getName()+"--->"+arg0.getValue()+arg0.getServletContext().getAttribute(arg0.getName())); |
感知监听(都与HttpSession相关的)
1.它用来添加在javaBean上,而不是添加带三大域上的。
2.这两个监听不需要在web.xml中配置
HttpSessionBindingLintener:添加在javaBean上,javaBean就知道自己是否添加到了Session中。
【以userBean为例】
public class User implements HttpSessionBindingListener { //添加该bean到session中时调用 public void valueBound(HttpSessionBindingEvent arg0) { } //将该Bean移出session时调用 public void valueUnbound(HttpSessionBindingEvent arg0) { } }
页面1 <% session.setAttribute(“user”,new User()) %> 页面2 <% session.RemoveAttribute(“user”) %> |
Session自己的序列化有关。
第一个页面: 存一个session<% session.setAttribute("name", "lsd"); %> 第二个页面:<h2>取一个sessionh2> <% out.print(session.getAttribute("name")); %>
观察tomcat的目录 location\项目\多一个sessions文件【序列化文件】 手动关闭序列化 在 context.xml里添加 |
在服务器中,这叫钝化和活化
一般的运用场景,淘宝的大批量用户登录,每一个用户一个session对象,session存放在内存中,内存迟早爆炸,在用户登录后不再操作session,而是预览商品,我们就可以让该session对象从内存变成物理地址,保存到指定的路径【钝化】,而当我们想使用的时候该对象就会【活化】
自己配置钝化/活化 config.xml
//如果session在1分钟内没有使用 那么tomcat就会将它钝化 //把session钝化的文件路径为 localhost\项目\mySession\钝化的文件
|
最后一个监听
如果某个类实现了HttpSessionActivationListener接口后,当对象随着session被钝化和被活化
//活化 当对象感知被活化时调用 publicvoid sessionDidActivate(HttpSessionEvent arg0) { // TODO Auto-generated method stub System.out.println("我和session一起手拉手回来了"); }
//钝化 当对象感知被钝化时调用 publicvoid sessionWillPassivate(HttpSessionEvent arg0) { // TODO Auto-generated method stub System.out.println("我和session一起呗钝化了");
} |
国际化
什么是国际化?
就是把页面中的中文 更具不同国家的人访问 变成不同的语言!
理解国际化
想把页面中的中文修改 那么就不能使用硬编码 而使用变量
什么东西可以存放大量的配置信息?
Property
创建配置文件 放在资源目录下
res_zh_CN.properties 【其中res为基本名称 zh_CN为地区部分 所有的配置文件的基础名要一样】
loginpage 注册页
username 用户名
pwd 密码
login 登录
res_en_US.properties
loginpage LoginPage
username UserName
pwd PassWord
login Login
ResourceBundle类【用来解析语言配置文件中的内容】
如何创建
参数1代表配置文件的基本名称
参数2代表Locale对象
ResourceBundle rb=ResourceBundle.getBundle(参数1,参数2);
Locale类
创建Locale类对象
1.new Locale(“zh”,”CN”);
2. Locale.China;
Test测试
Locale lo=Locale.CHINA; ResourceBundle rb=ResourceBundle.getBundle("res", lo); System.out.println(rb.getString("loginpage")); System.out.println(rb.getString("username")); System.out.println(rb.getString("pwd")); System.out.println(rb.getString("login")); |
jsp页面测试 <body> <% //通过请求头获取Locale对象 Locale lo= request.getLocale(); //解析对应语言的配置信息 ResourceBundle rb=ResourceBundle.getBundle("res", lo);
%> <h2><%=rb.getString("loginpage") %>h2> <form action="${pageContext.request.contextPath}/szLin/a.jsp" method="get"> <%=rb.getString("username") %><input type="text" name=name><br> <%=rb.getString("pwd") %><input type="password" name="pwd"><br> <input type="submit" value="<%=rb.getString("login") %>"> form> body> |
过滤器是javaWeb的三大组建之一。他与servler非常的相似,不过他是用来拦截请求的,而不是用来处理请求的。
当用户请求某个servlet时,会先执行部署在这个请求上的Filter,如果Filter‘放行’,那么会继续执行用户请求的servlet,如果Filter不‘放行’,那么就不会执行用户请求的servlet。
它会在一组资源【jsp,html,servlet……】前面执行
它可以让请求得到目标资源,也可以让你请求不到
*过滤器就是做拦截功能的
如:没有登录的情况,不让你做任何的请求!
过滤器如何编写!
1.写一个类实现javax.servlet.Filter接口
2.在web.xml中进行配置【配置的格式与servlet及其相似】
过滤器的生命周期:
实例化:服务器开启的时候,由服务器自己创建过滤器对象
初始化:调用init方法初始化
过滤:调用doFilter方法进行过滤
销毁:调用destory方法进行销毁
Filter中的方法:
Void inti(); //服务器创建对象后,马上执行。
Void destory(); //销毁之前执行。在服务器关闭的时候销毁
Void dofilter(ServletRequest,ServletResponse)//每次过滤都会执行
Filter与servlet一样都是单列的!
Filter只的类型
FilterConfig
Filter接口中的init()方法的参数类型,他的功能与ServletConfig相似,
与web.xml文件中的配置文件信息对应,下面为其的方法↓
String |
getFilterName() |
String |
getInitParameter(String name) |
Enumeration |
getInitParameterNames() |
ServletContext |
getServletContext() |
Web.xml
<filter> <filter-name>lsdfilter-name> <filter-class>web.filter.FilterAfilter-class> <init-param> <param-name>nameparam-name> <param-value>lsdparam-value> init-param> <init-param> <param-name>pwdparam-name> <param-value>123param-value> init-param> filter> |
ServletRequest和ServletResponse
不解释了!
FilterChain
FilterChain类是dofilter()方法的一个参数,该参数类型只有一个方法即:dofilter(ServletRequest,ServletResponse);
dofilter();方法相当于‘放行’,让请求的对象访问目标资源!
【相当于调用servlet的service()方法】
但这么说不严谨,其实调用方法的意思是‘我(当前的Filter)给你放行了’,但不代表其他人(其他的Filter)也放行
也就说:一个目标资源上,可以不说多个多虑器,
好比刘升东上学的路上遭遇了多次打劫!
其中第一伙人打劫完 放行了,不代表第二伙人也放行
所以调用FilterChain类的doFilter()方法表示执行下一个过滤器,或执行目标资源
如果每有下一个过滤器那么执行目标资源,有下一个过滤器执行下一个过滤器。
多个过滤器的执行顺序
一个目标资源可以指定过个过滤器,过滤器的执行顺序是在web.xml文件中的部署顺序:
四种拦截方式:
过滤器的4种拦截方式:reqeust,forward,include,error
Reqeust:直接访问目标资源时执行过滤器,包括:在地址栏中直接访问,表单提交,超链接,重定向,只要在地址栏中能看到目标路径的就是request。【不写 默认的就是这个玩意】
Forward:转发访问执行的过滤器 包括:
RequestDispatcher.forward(*,*);
Include:包含访问执行的过滤器 包含:
RequestDispatcher.include(*,*);
Error:当目标资源在web.xml中配置了
表示真的出现了异常,转发到目标资源时 执行过滤器。
在
<filter-mapping> <filter-name>filterBfilter-name> <url-pattern>/*url-pattern> <dispatcher>REQUESTdispatcher> //相配几个自己看着办 <dispatcher>FORWARDdispatcher> filter-mapping> |
Error的方式不同 error的例子
Web.xml <filter-mapping> <filter-name>filterBfilter-name> <url-pattern>/*url-pattern> <dispatcher>ERRORdispatcher> filter-mapping>
、 <error-page> <error-code>500error-code> <location>/500.jsplocation> error-page>
Index.jsp <body> <% int i=1/0; %> body> |
过滤器的应用场景
1.执行目标资源之前做的预处理工作,如:设置统一的编码,统计访问次数,这种通常都会‘放行’,只是在目标资源执行之前做了一些准备工作。
2.通过条件的判断是否‘放行’例如:没登录的情况下进行 操作。
判断之后通过才 ‘放行’
3.在目标资源执行后,做一些后续的特殊处理:例如把目标资源输出的数据进行特殊处理!
分ip统计站点的访问次数
Ip |
count |
192.168.1.100 |
50 |
192.168.1.3 |
20 |
统计工作需要在所有资源之前执行,那么就可以放在Filter中。
我们这个过滤器不打算做拦截操作,我们只需要用来做统计
用什么来装载统计的数据呢?Map
整个网站只能有一个 Map
Map什么时候创建?(使用ServletContextListener,在服务器启动时创建,并存到servletContext中去)
Map的数据需要在Filter中用来保存数据
Map需要在页面中使用,打印Map的数据
粗粒度权限控制
说明:
给出三个页面index.jsp user.jsp vip.jsp
index.jsp 谁都可以访问没有权限
user.jsp 只有登录的用户才能访问
vip.jsp 只有会员才能访问
分析:如果当前没有人登录只能访问游客页
如果当前有人登录但不是会员可以访问 游客模块/用户模块
如果登录的是会员(名字包含lsd的就是会员)可以访问会员模块/用户模块/游客模块
当我们登录成功后直接将信息存入 session中
如何进行拦截:
1.当用户访问游客模块。无须拦截
2.当用户访问用户模块 进行拦截,判断session中是否存在用户
不存在给出提示,返回登录页
3.当用户访问会员模块 进行拦截,判断session中是否存在会员
不存在给出提示,返回登录页
文件上传的作用:
网盘!就是文件的上传下载。
注册会员,头像上传。
文本编辑时的,附件
……..
文件上传对表单的特殊要求
1.必须是表单,不是超链接
2.表单的method必须是post,而不能是get
3.表单的enctype属性必须输multipart/form-data 【多部件数据】
4.在表单添加file表单元素, 即
文件上传对servlet的要求
首先我们要肯定一点,文件上传表单的数据被封装在了request对象中。
Request.getParameter(Stringname)方法获取指定表单元素的value值,但是文件上传表单已经不是字符内容了,所以该方法失效!
这时可以使用reqeust的getInputStream() 方法来湖区ServletInputStream对象,
它是inputStream的子类,这ServletInputStream对象对应的是整个表单。说明我们需要解析这个流,来获取上传的文件/普通表单的值
上传类型的表单分析
1.给一个部件,表示一个表单元素
2.一个部件中自己包含请求头/空行/请求体
3.普通的部件
>一个头:Content-Disposition:包含 name=”xxx” 即表单元素的名称
>体就是表单元素的 值
4.文件部件
>两个头:Content-Disposition:包含 name=”xxx” 即表单元素的名称
还有一个filename=”xxx” 表示上传文件的名字
Content-Type:它是上传文件的MIME类型, 如image/jpeg
>体就是上传文件的内容。
commons-fileupload
1.commons-fileupload-1.2.2.jar 核心包
2.commons-io-1.4.jar 依赖包
这个小组件,它会帮我们解析reqeust中的上传数据,解析后的结果多个表单项【多个部件】,每一个分装到FiltItem对象中 我们只需要 调用FiltItem的方法就能得到 普通域/上传域的所有东西。
实现上传的三步骤:
相关类:
工厂:DiskFileLtemFactory
解析器:ServletFileUpload 【用来解析request上传的数据 但还不需要工厂的帮忙】
表单项:FileItem 【每一个表单元素 封装一个FileItem对象】
FiltItem类中的方法
Boolean isfromField() 是否为普通表单项 返回true为普通项 false文件项
String getFiledName() 返回当前表单项的名称 【也就是普通表单的name的值/和file的name值】
String getString(String charset) 返回表单项的值【也就是普通表单的value值】
String getName() 返回上传文件的 文件名【也就是上传后 显示在域上的值】
Long getSize() 返回上传文件的字节数
StringgetContentType() 获取上传文件的类型
InputStream getInputStream();返回上传文件对应的输入流
Void writer(Filefile) 把上传的内容保存到指定的路径
上传的细节
1.为了保证文件的安全 可以把文件保存到WEB-INF下
目的就是不让浏览器直接访问资源【不全是所有的文件都放在WEB-INF下】
request.getSession().getServletContext().getRealPath("/WEB-INF/upload"); |
2.文件的名称问题
有的浏览器上传的文件名是文件在电脑中的绝对路径 而不单单是文件名
int index=fileName.lastIndexOf("\\"); if(index!=-1){ fileName=fileName.substring(index+1); } |
3.乱码问题
文件名/普通表单元素的value值都有可能出现乱码
request.setCharacterEncoding("utf-8");起到作用 是因为fileUpload内部调用
request.getCharacterEncoding();已经获取到了请求的编码。
通过解析器指定编码 :upload.setHeaderEncoding("utf-8");
4.文件的同名问题: 我们需要为这个文件添加一些前缀让他成为服务器中的唯一 uuid【唯一性工具】
publicclass UUIDUtils { publicstatic String getUUID(int num){ if(num<1){ returnnull; }
StringBuffer sb=new StringBuffer();
for(int i=0;i sb.append(UUID.randomUUID().toString().replace("-", "")); } return sb.toString(); }
publicstaticvoid main(String[] args) { System.out.println(getUUID(1)); } } |
5目录问题:
不能在一个目录下放太多的文件【不方便搜索】
分组:
首字符分文件夹:
时间分文件夹:
日期分文件夹:
哈希值分文件夹:
获取文件的hash值 调用hashCode();
它是一个16进制的值:0-9,A-F
如:1B25EE6CCA789 截取前2位 第一个字符为目录 第二个字符为子目录
/1/B 保存的路径
6.上传文件的大小限制
单个文件大小
//创建解析器 ServletFileUpload upload=new ServletFileUpload(fileItemFactory); //限制上传文件的大小为100K upload.setFileSizeMax(1024*100);
如果超出了会在解析的时候包异常 parseRequest() 异常为FileUploadBase.FileSizeLimitExceededException |
整个请求表单的大小
//创建解析器 ServletFileUpload upload=new ServletFileUpload(fileItemFactory); //限制上传文件的大小为100K upload.setSizeMax(1024*100);
如果超出了会在解析的时候包异常 parseRequest() 异常为FileUploadBase.SizeLimitExceededException |
1.下载就是向客户端响应的字节数据
原来我们响应的都是HTML的字符数据
把一个文件变成字节数组,使用response.getOutPutStream();来响应给浏览器。
2.下载的要求
两头一流
Content-Type:你传递给客户端的文件是什么类型 如 imgge/pjpeg
通过文件的名称调用ServletContext的getMimeType方法得到文件类型
Content-Disposition:他默认值lnline,表示在浏览器中直接打开下载的文件
修改其属性值 如:attachement;filename=xxx; filename后面跟随的就是显示在下载框中的文件名称!
流:要下载的流
自己new一个输入流即可
下载的细节
显示在下载框中的中文名称会出现乱码
FireFox Base64位
其他的 大部分 用的 URL编码
通用的编码:
String fromatName=new String(downFileName.getBytes(“GBK”),”ISO-8859-1”);
一张用户表
Id name pwd headPhone
1 lsd 123 upload/116165164616sdasdaslsd.png
登录成功 进入主页 遍历用户数据 在页面中显示
Id |
Name |
Pwd |
headPhone |
1 |
Lsd |
123 |
15616151.png |
2 |
Zqy |
456 |
13131321.png |
发邮件是从客户端把邮件发送到邮件的服务器
收邮件从邮件的服务器端把邮件下载到客户端
我们常见的邮箱 163 126 qq sohu sina
邮件协议概述
与http协议相同,收发邮件也需要传输协议
SMTP:简单的邮件传输协议 发邮件
POP3:邮局协议 收邮件
IMAP:因特网消息访问协议 收发邮件
邮件服务器名称
SMTP 服务器的端口为25 服务器名称为 SMTP.xxx.xxx
POP3 服务器的端口为110 服务器名称为 POP3.xxx.xxx
例如:
163 smtp.163.com和pop3.163.com
126 smtp.126.com和pop3.126.com
qq smtp.qq.com和pop3.qq.com
javaMail
javaMail是什么?
是由sun公司提供的专门针对邮件的API
javaMail中的主要类
javax.,mail.session
表示会话,即客户端与邮件服务器之间的一次会话 想获得会话需要给出账号和密码,当然还要给出服务器名称。
MimeMessage
表示邮件类,它是Message,它包含邮件的标题,内容,收件人,发件人,附件。
Transport
用来发送邮件的
使用javaMail来发送一个邮件
三步走
1.获得session
2.创建MimeMessage
3.发送
什么是ajax
AJAX(Asynchronous javaScript and xml)翻译:异步的js和XML,即使用js的语言与服务器进行异步交互,传输的数据为XML【不单单只是XML类型的数据,text纯文本
Json 它是js提供的一种数据交互格式,也是最受欢迎的】
AJAX还有一个最大的特点就是,当服务器响应时,不要刷新整个浏览器,而是可以局部刷新【刷新网页的一部分数据】,这个特点给用的感受就是 不知不觉中完成了请求和响应
同步交互与异步交互的差异
同步:
发一个请求,就要等待服务器的响应结束,然后才能发送第二个请求,中间这段时间就是【什么事都干不了】
刷新的是整个页面
异步:
发送一个请求,无须等待服务器的响应,然后就可以发第二个请求!
使用js接收服务器响应的数据,实现局部刷新。
Ajax常见应用场景
百度的搜索框
用户注册时 名字相同的验证
评论的加载
根据条件筛选商品
分页
AJAX的优缺点
优点:
Ajax使用js技术项服务器发送异步请求
Ajax无须刷新整个页面
因为服务器响应的不是整个页面,而是页面中的局部,所以ajax性能高
缺点:
Ajax并不适合所以的场景,很多时候还是同步交互
Ajax性能高,但是无形中 向服务器发送了多次请求 导致服务器压力增大
因为Ajax在浏览器中使用js技术完成的,所以还需要处理浏览器兼容问题。
如何使用ajax就是实现异步请求【4步骤】
1.第一步(得到XMLHttpRequest)
Ajax其实只需要学习一个对象XMLHttpRequest,等于掌握了ajax!
得到XMLHttpRequest
》大多数浏览器都支持:var xmlHttp=newXMLHttpRequest();
》IE6.0:var xmlHttp=new ActiveXObject(“Msxml2.XMLHTTP”);
》IE5.5以及更早的版本:var xmlHttp=new ActiveXObject(“Microsoft.XMLHTTP”);
创建一个函数 更具不同的浏览器创建不同的XMLHttpRequest对象
function createXMLHttpRequest(){ try{ return new XMLHttpRequest; }catch(e){ try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ alert("孩子!你用的到底是啥浏览器 这个吊"); throw e; } } } } |
2.第二步(打开与服务器的连接)
Var xmlHttp =createXMLHttpRequest(); |
xmlHttp.open(); 打开与服务器的连接,它还需要三个参数
》请求方式:get/post
》请求的url:指定服务器的资源【servlet】如:/2017-11-25/servletA
》请求是否为异步:如果为true 就是异步请求 false同步
总终:xmlHttp.open(“GET”,”/2017-11-25/servletA”,true);
3.第三步(发送请求)
xmlHttp.send(null);如果不给可能会造成部分浏览器无法发送请求!
》参数:就是请求体的内容!如果是get请求,必须给出null;
4.第四步(通过绑定监听获取响应内容)
在xmlHttp 对象的一个事件上注册监听器:onreadystatechange
xmlHttp 对象一共有5个状态:
》0状态:刚创建,还没调用open()方法
》1状态:请求开始,调用了open()方法,但是还没调用send()方法
》2状态:调用完了send()方法
》3状态:服务器开始响应,但是不表示响应结束
》4状态:服务器响应结束!
如何得到xmlHttp 对象的状态:
Var status=xmlHttp.readyState; //值可能是0 1 2 3 4
服务器的响应状态码
Var responseStatus=xmlHttp.status;//值可能是 200 303 404 500 505
得到服务器响应的内容
Var content=xmlHttp.responseText;// 得到服务器响应的文本格式的内容
Varcontent=xmlHttp.responseXml; // 得到服务器响应的xml文本格式的内容
var xmlHttp=createXMLHttpRequest();
//xmlHttp状态一旦发生改变就是调用本方法 xmlHttp.onreadystatechange(){ //双重判断判断xmlHttp是否为状态4 且响应码是否为200 if(xmlHttp.readyState==4&&xmlHttp.status==200){ //获取服务器的响应内容 Var content=xmlHttp.responseText; } } |
第一例: 使用get请求 实现局部刷新
servletA
response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("我是servletA的数据"); out.flush(); out.close(); |
Jsp
<button id="btn">获取服务器的数据button> <h1 id="h1">h1>
<script type="text/javascript"> //更具不同的浏览器创建不同的 XMLHttpRequest对象 function createXMLHttpRequest(){ try{ return new XMLHttpRequest; }catch(e){ try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ alert("孩子!你用的到底是啥浏览器 这个吊"); throw e; } } } }
//文档加载完后执行 window.οnlοad=function(){ //获取按钮的元素 var btn=document.getElementById("btn"); //给该元素绑定点击事件 btn.οnclick=function(){ //1.得到XMLHttpRequest对象 var xmlHttp=createXMLHttpRequest(); //2.打开与服务器的连接 xmlHttp.open("GET","/2017-11-25/servletA",true); //3.发送请求 xmlHttp.send(null); //4.给异步对象绑定onreadystatechange事件 xmlHttp.onreadystatechange=function(){ //双重判断判断xmlHttp是否为状态4 且响应码是否为200 if(xmlHttp.readyState==4&&xmlHttp.status==200){ //获取服务器的响应内容 var content=xmlHttp.responseText; //获取h1的元素 var h1=document.getElementById("h1"); h1.innerHTML=content; } } } } script> |
第二例:发送post请求
1.xmlHttp.open(“POST”,”/2017-11-25/servletA”,true);
2.设置请求头 content-type 【post请求application/x-www-form-urlencoded】
当ajax发送post请求时,添加请求参数
xmlHttp.send(“useranem=lsd,psd=123”); //发送请求时指定请求体。
ServletB
response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("姓名:"+request.getParameter("username")); out.flush(); out.close(); |
Ajax2.jsp
//2.*****打开与服务器的连接 xmlHttp.open("POST","/2017-11-25/servletB",true); //****设置post时的content-type的请求头 xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //3.******发送请求 xmlHttp.send("username=lsd&pwd=123"); |
第三例: 注册表验证是否同名
1.编写jsp
1.给出注册表单
2.给用户名输出框添加onblur事件
3.获取文本框的值,通过ajax发送给服务器,得到服务器判断的结果
接收到的是1,给用户提示是用户名已被注册
接收到的是0,直接通过
2.Servlet
1.获取用户传入的用户名
2.去数据库查找是否存在这个名字
3.将结果返回给异步对象
存在返回1
不存在返回0
Jsp
<form action="" method="post"> 用户名:<input type="text" name="name" id="name"><span id="mess">span><br> 密码:<input type="password" name="pwd"><br> <input type="submit" value="注册"> form>
<script type="text/javascript"> //更具不同的浏览器创建不同的 XMLHttpRequest对象 function createXMLHttpRequest(){ try{ return new XMLHttpRequest; }catch(e){ try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ alert("孩子!你用的到底是啥浏览器 这个吊"); throw e; } } } }
//文档加载完后执行 window.οnlοad=function(){ //获取按钮的元素 var name=document.getElementById("name"); //给该元素绑定点击事件 name.οnblur=function(){ //1.得到XMLHttpRequest对象 var xmlHttp=createXMLHttpRequest(); //2.*****打开与服务器的连接 xmlHttp.open("POST","/2017-11-25/servletC",true); //****设置post时的content-type的请求头 xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); //3.******发送请求 xmlHttp.send("username="+name.value); //4.给异步对象绑定onreadystatechange事件 xmlHttp.onreadystatechange=function(){ //双重判断判断xmlHttp是否为状态4 且响应码是否为200 if(xmlHttp.readyState==4&&xmlHttp.status==200){ //获取服务器的响应内容 var content=xmlHttp.responseText; //获取信息的提示区域 var mess=document.getElementById("mess"); //更具的到的结果给用户相应的提示 if(content=="1"){ mess.innerHTML="用户名已被注册"; }else{ mess.innerHTML=""; } } }; }; }; script> |
servletC
request.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); //获取用户的传入的用户名 String name=request.getParameter("username"); //判断数据库是否存在【数据库就一人 lsd】 if(name.equals("lsd")){ out.print("1"); }else{ out.print("0"); } out.flush(); out.close(); |
示例4 使用xml接收服务器的数据
要注意两点
服务器端的
设置响应头:contentType 其值为 text/xml;charset=utf-8
客户端的:
Var doc=XmlHttp.responseXML; //得到的是Document对象
Servlet
response.setContentType("text/xml;charset=utf-8"); String xml=" " " " " ""+ "";
PrintWriter out = response.getWriter();
out.println(xml); out.flush(); out.close(); |
Jsp
<script type="text/javascript"> //更具不同的浏览器创建不同的 XMLHttpRequest对象 function createXMLHttpRequest(){ try{ return new XMLHttpRequest; }catch(e){ try{ return new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ return new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ alert("孩子!你用的到底是啥浏览器 这个吊"); throw e; } } } }
//文档加载完后执行 window.οnlοad=function(){ //获取按钮的元素 var btn=document.getElementById("btn"); //给该元素绑定点击事件 btn.οnclick=function(){ //1.得到XMLHttpRequest对象 var xmlHttp=createXMLHttpRequest(); //2.打开与服务器的连接 xmlHttp.open("GET","/2017-11-25/servletD",true); //3.发送请求 xmlHttp.send(null); //4.给异步对象绑定onreadystatechange事件 xmlHttp.onreadystatechange=function(){ //双重判断判断xmlHttp是否为状态4 且响应码是否为200 if(xmlHttp.readyState==4&&xmlHttp.status==200){ //获取服务器的响应内容 var doc=xmlHttp.responseXML; //查询文档下名为student节点的集合 中的第一个 var ele=doc.getElementsByTagName("student")[0];
//更具节点的属性 得到对应的值 var id=ele.getAttribute("stuno");
var name; var gae; var sex;
//处理差异 if(window.addEventListener){ name=ele.getElementsByTagName("name")[0].textContent;//大部分浏览器 }else{ name=ele.getElementsByTagName("name")[0].text;//IE浏览器 }
if(window.addEventListener){ age=ele.getElementsByTagName("age")[0].textContent;//大部分浏览器 }else{ age=ele.getElementsByTagName("age")[0].text;//IE浏览器 }
if(window.addEventListener){ sex=ele.getElementsByTagName("sex")[0].textContent;//大部分浏览器 }else{ sex=ele.getElementsByTagName("sex")[0].text;//IE浏览器 }
document.getElementById("h1").innerHTML=name+"--"+age+"--"+sex;
} }; }; }; script> |
实例5 省市联动
表省
Id name sx
市
Id name sx
Js->Jquery ajax的一套封装
我们想这么来架构:
Utils BaseDao
Po Student
Dao StudentDao
Biz StudentBiz
Web StudentServlet (做学生模块的所有请求处理方法:增删改查……)
我们可以这么来:
1.客户端发送请求是,必须多给一个参数,用来说明要调用的方法。
2.处理请求的方法的签名必须与service相同,即返回值/参数/申明的异常相同
3.客户端必须传递名为method的参数【为了统一接收】
代码如下↓:
Index.jsp 学生模块
servlet public class StudentServlet extends HttpServlet {
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method=request.getParameter("method"); if(method!=""&&method!=null){ if(method.equals("add")){ add(request,response); }else if(method.equals("delete")){ delete(request,response); }else if(method.equals("update")){ update(request,response); }else if(method.equals("select")){ select(request,response); } } }
//增 protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add.........................."); }
//删 protected void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete.........................."); }
//改 protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("update.........................."); }
//查 protected void select(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("select.........................."); }
} |
缺陷:我等等再增加一个方法叫uniqueStudent() 你就要干什么事情?
你必须为这个方法添加一个 else if() 分支! 很没有灵性。
设想:更具我们传去的方法名 自动的调用对应的方法!
确定的问题:调用的方法名能不能确定? 能
在哪个类里面调用能不能确定? 能
既然都可以,我们可以通过反射来调用器对应的方法
1.获得当前类的class对象
2.通过当前类的class对象的getMethod()方法查找是否存在你想调用的请求方法.
3.有该请求方法就调用执行 没有就抛出自定义异常信息。
代码如下↓
Index.jsp 学生模块
Servlet public class StudentServlet extends HttpServlet {
@Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method=request.getParameter("method");
//判断传入的方法名是否为空 if(method==null||method.trim().isEmpty()){ throw new RuntimeException("你没有传递方法!我不知道那什么去呵护你!!!!"); }
//得到当前类的class对象 Class c=this.getClass();
//什么method对象 Method m=null;
try { //查找你想要调用的 处理请求的方法
m= c.getMethod(method,HttpServletRequest.class,HttpServletResponse.class); } catch (Exception e) { throw new RuntimeException("你调用的方法"+method+"(HttpServletRequest request, HttpServletResponse response)!它不存在!!!"); }
//找到了 就可以调用了 try { m.invoke(this, request,response); } catch (Exception e) { throw new RuntimeException("你调用的方法内部发生了错误!!!!"); }
}
//增 public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("add.........................."); }
//删 public void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("delete.........................."); }
//改 public void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("update.........................."); }
//查 public void select(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("select.........................."); } |
每个servlet里做完了事 基本都要做跳转,能不能做一个标识,让其自动的转发或重定向?
确定问题:转发和重定向什么时候执行?【请求体结束】
如何获取方法里的标识?
代码如下↓
try { //调用你想要处理请求的方法 String result=(String)m.invoke(this, request,response);
//判断返回的是否为空 if(result==null||result.trim().isEmpty()){ return; }
/* * 查看返回的字符串是否包含冒号,如果过没有表示有误 * 如果有,使用冒号截取分割字符串。得到前缀和后缀 * 其中前缀如果是z就是转发/为c就是重定向 后缀就是转发/重定向的路径 */
//判断字符串里是否包含冒号 if(result.contains(":")){ //使用冒号分割字符串 //获取冒号的位置 int index=result.indexOf(":"); //获得前缀 String bf=result.substring(0,index); //获得后缀 String path=result.substring(index+1); //如果前缀为c表示重定项 反之为转发 if(bf.equals("c")){ //重定向 response.sendRedirect(request.getContextPath()+path); }else if(bf.equals("z")){ //转发 request.getRequestDispatcher(path).forward(request, response); }else{ throw new RuntimeException("你指定的操作"+bf+"当前版本不支持!!"); }
}else{ throw new RuntimeException("你的跳转操作有问题!!!!"); } |
每一个业务的servlet,都需要如此写,我们可以吧servlet里的所有东西放在Baseservlet中,其他的servlet去继承即可 最终其他的servlet只需要专注写自己业务的 处理请求的方法即可
Public class BaseServlet extends HttpServlet}{ //我们上面的两端代码之和 }
其他的servlet模块 Public class StudnetServlet extends BaseServlet(){ //只需写自己的 处理请求的方法即可!! 如: Public String add(HttpServletRequest request, HttpServletResponse response){ //接收参数 处理请求 //跳转 格式 c:/index.jsp 重定项到index.jsp // z:/index.jsp 转发到index.jsp Reuen “c:/index.jsp”; } |
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class BaseServlet extends HttpServlet {
@SuppressWarnings({ "rawtypes", "unchecked" })
public void service(HttpServletRequest request,HttpServletResponse response){
String method=request.getParameter("method");
//判断方法名是否 为空
if(method==null||method.trim().isEmpty()){
throw new RuntimeException("缺少方法名传递!");
}
//得到当前类的class对象
Class c=this.getClass();
Method m=null;
try {
m=c.getMethod(method, HttpServletRequest.class,HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException("调用的方法"+method+"不存在!");
}
String result=null;
try {
result=(String) m.invoke(this, request,response);
} catch (Exception e) {
throw new RuntimeException("调用的方法"+method+"内部错误!");
}
if(result==null||result.trim().isEmpty()){
throw new RuntimeException("方法"+method+"返回路径为空!");
}
try {
//判断字符串里是否包含冒号
if(result.contains(":")){
//使用冒号分割字符串
//获取冒号的位置
int index=result.indexOf(":");
//获取前缀
String bf=result.substring(0,index);
//获取后缀
String path=result.substring(index+1);
if(bf.equals("c")){
response.sendRedirect(request.getContextPath()+path);
}else if(bf.equals("z")){
request.getRequestDispatcher(path).forward(request, response);
}else{
throw new RuntimeException("参数前缀异常!");
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
四大特性:
1.原子性(Atomicity):事务中的所有操作是不可分割的原子单位,事务中的操作要么都成功,要么全失败。
2.一致性(Consistency):事务执行后,数据库状态与其他业务规则保持一致,如转账,无论事务成功与否,参加转账的两个账户的金额之和不会发生变化
3.隔离性(Islation):隔离性是指在开发中的线程安全问题【并发】,不同的事务之间应该隔离开来,使每一个并发中的事务不会互相干扰。
4.持久性(Durability):一旦事务成功,事务中的所有数据将会被持久化到数据库中。
JDBC事务
在jdbc中处理事务,都是通过Connection完成的。
同一个事务中所有的操作,都是使用同一个Connection对象
JDBC中的事务操作
Connection的三个方法与事务相关
setAutoCommit(boolean) 设置是否自动提交事务。
Commit();提交事务
Rollback();回滚事务
Jdbc处理事务的代码格式
Try{
Conn.setAutoCommit(false);//开启事务
……
…..
Conn.commit();//提交事务
}catch(Exception e)(
……….
Conn.rollback();//回滚事务
)
保存点的作用是允许事务回滚到指定的保存点的位置。
【回滚到指定的保存点,并没有结束事务,只有回滚整个事务才算结束事务】
Connection类的设置保存点的方式,以及回滚到保存点的方式
设置保存点:Savepointconn.setSavepoint();
回滚保存点:conn.rollback(Savepoint);
Jdbc处理事务时使用保存点的代码格式
Try{
Conn.setAutoCommit(false);//开启事务
……
Savepoint sp=conn.setSavepoint();// 设置保存点
…..
Conn.commit();//提交事务
}catch(Exception e)(
……….
Conn.rollback();//回滚事务
)catch(*****){
………
Conn.rollback(sp);//回滚到设置保存点的位置
}
并发事务问题:
并发导致事务的问题大致为5种,其中两类是更新问题,三类是读问题。
1.脏读:读到了另一个书屋的未提交更新的数据。即读到了脏数据【我添加一个商品,用户去查看,并没看的见】
2.不可重复读:对同一条数据两次读取不一致,因为另一个事务对该记录做了修改。
3.幻读:对同一条数据两次读取不一致,因为另一个事务插入了一条数据
四大隔离级别:
1.SERIALlZABLE(串行化)
不会出现任何的并发问题,因为它是对同一数据的访问是串行的非并发访问。
性能最差
2.REPEATABLE READ(可重读)【MySql里默认的隔离机制】
防止脏读和不可重复读,不能处理幻读问题
性能比SERIALlZABLE
3.READ COMMITED(读已提交的数据)【Oracle里默认的隔离机制】
防止脏读,没有处理可重复/幻读问题
性能比REPEATABLEREAD
4.READ UNCOMMITTED(读未提交数据)【什么都不做】
可能出现任何的并发问题
性能最好
JDBC设置隔离级别
Conn.setTransactionloslation(int level) 【一般我们不会去修改默认的隔离级别】
参数:
Connection.TRANSACTION_READ_UNCOMMITTED 1
Connection.TRANSACTION_READ_COMMITTED 2
Connection.TRANSACTION_REPEATABLE_READ 4
Connection.TRANSACTION_SERIALIZABLE 8
总结:
事务的特性:ACID
事务的操作流程:开事务 结束事务【正常提交/异常回滚】
事务的隔离级别:4个【多事务并发时才需要】
数据库连接池
连接池的概念:
用池来管理Connection,可以重复使用Connection。我们就不需要自己来创建Connection,而是通过池来获取Connetion,用完后调用close()方法将Connection归还给池子
JDBC数据库连接池(DataSource)
Java为数据库连接池提供了公共的接口:javax.sql.DataSource.
各个厂商可以让自己的连接池实现这个接口,这样程序就可以切换不同的连接池。
什么是DBCP?
DBCP是Apache提供的一款开源免费的数据库连接池。
DBCP的使用(DBCP的池类BasicDataSource)
C3p0也是开源免费的连接池,c3p0被许多人看好。
C3P0的使用(C3P0的池类是:ComboPooledDataSource)
配置文件要求:
1.文件名必须叫:c3p0-config.xml
2.文件位置:src同目录下的资源文件夹内
【见jar包里的配置】
通过配置文件 在类里获取Connection对象
工具包的修改【连接的方式】
1.导入jar包【3个】
2.在资源目录下创建c3p0-config.xml配置文件
3.修改原先的BaseDao类
publicclass JdbcUtlis { //创建连接池对象 privatestatic ComboPooledDataSource dataSource=new ComboPooledDataSource();
//获取连接池的连接 publicstatic Connection getConnection() throws SQLException{ returndataSource.getConnection(); }
//获取连接池 publicstatic DataSource getDataSource(){ returndataSource; } } |
DAO的修改
Common-dbutils.jar[apache提供的简化jdbc的jar包]
QueryRunner【工具类 】
Update方法:
Int update(Stringsql,Object….param);-à可执行增删改的语句
Int update(Connectioncon,String sql,Object….param);à需要使用者提供连接
//增—删-改 一样 publicint savaStu(Student stu) throws SQLException{ //创建工具类对象 QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); //sql语句 String sql="insert into stu values(?,?,?)"; //设置参数 Object [] params={stu.getSid(),stu.getSname(),stu.getClassno()}; //调用工具类的方法 return qr.update(sql, params); } |
Query方法:
T query(Stringsql,ResultSetHandler rsh,Object params)--à执行查询
先得到resultSet结果集,然后调用rsh的 handle()方法 把结果集转换成你需要的类型。
T query(Connectioncon,String sql,ResultSetHandler rsh,Object params)--à执行查询
//查 根据id查询 public Student beanStudent(Integer id) throws SQLException{ QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); String sql="select * from stu where sid=?"; Object [] params={id}; //调用工具类的查询方法 return qr.query(sql, new BeanHandler<>(Student.class), params); } |
ResultSetHandler 接口的实现类【返回不同的结果集】
1.BeanHandler(单行) ---》构造器需要一个Class类型的参数,用来把一行的结果转换为指定类型的 javaBean对象。【全参/无参/JavaBean属性规范】
2.BeanListHander(多行)----》构造器也需要一个Class类型的参数,用来把一行结果集转换成一个javaBean对象,那么多行就是转换成list对象,一堆JavaBean
【查询全部信息】
//查询全部信息【多行多列】 public List QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); String sql="select * from stu"; return qr.query(sql,new BeanListHandler<>(Student.class)); } |
3.MapHandler(单行)---》把一行结果转换成Map对象
({sid:1,sname:lsd,classno:1})
【查询lsx种子】
//查询刘西的具体信息 public Map QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); String sql="select * from stu where sname=?"; Object [] params={sname}; return qr.query(sql, new MapHandler(), params); } |
4.MapListHander(多行)*----》把一行数据转换成map,多行记录就是多个Map,即List
【查询全部】
//查询全部信息 public Listthrows SQLException{ QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); String sql="select * from stu"; return qr.query(sql,new MapListHandler()); } |
5.ScalaHander(单行单列)----》通常与聚合函数一起来使用 返回的是Object类型
【查询总条数】
public Object count() throws SQLException{ QueryRunner qr=new QueryRunner(JdbcUtlis.getDataSource()); String sql="select count(sid) from stu"; return qr.query(sql,new ScalarHandler()); } |