JavaWeb

常见的软件系统结构B/S  C/S

1.C/S

  C/S结构是客户端/服务器端(client/server)比如QQ,LOL

  需要编写服务器端的程序,以及客户端的,我们安装的qq包就是客户端程序

  缺点:软件更新时客户端与服务器端都要更新,服务器端更新时客户端无法使用,比较麻烦,你想要运行对应的客户端程序,硬件必须支持

  优点:安全心比较高【一对一的关系】

2.B/S

  B/S结构浏览器端/服务器端(Browser/server)

  优点:只需要编写服务器端,不需要维护浏览器,不需要硬件支持只要一个浏览器

  缺点:安全性比较差

 

Web资源【服务器资源  发布到服务器上的文件】

web资源的分类

   1静态资源:html【浏览器可以直接查看】

   2动态资源:jsp/servlet【需要先转换成html  再给游览器去渲染】

静态资源与动态资源的区别

JavaWeb_第1张图片

如何来访问web资源的【如何逛淘宝】

打开浏览器:输入URL

URL:协议名://域名:端口/路径  如:http://www.baidu.com/one/123.html

                 【域名里就是对应的服务器的ip地址】

Web服务器

  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概述

   Tomcat服务器是由Apache提供的,开源/免费的,由于Sun和其他公司参与到了Tomcat的开发中。所以最新的jsp/servlet规范总能在tomcat中体现出来。

当前最新的是Tomcat9.0.1,

Tomcat7 支持servlet3.0

Tomcat6 支持 servlet2.5

【企业开发中是否选择最新版?  一般用低版本】

 

Tomcat的安装,启动,配置

下载:tomcat网站   http://tomcat.apache.org

Tomcat分为解压版和安装版

安装版:一台电脑只能安装一个tomcat

解压版:无须安装,解压就能用,随你解压多少次

 

Tomcat的目录

Bin:存放的各种平台下的停止和启动tomcat的脚本文件

Conf:放置的tomcat服务器的各种配置文件

Lib:放置的是tomcat所需要的各种jar文件

Logs:放置的是tomcat运行时的日志文件

Temp:放置的是tomcat运行时 用于存放临时文件

Webapps:发布web应用时,默认情况下会将WEB文件放置在该目录下

Work:放置的是动态页面转换成静态页面的文件

     【由jsp生成的servlet文件】

LICENSE  许可证

NOTICE  说明书

 

启动和关闭tomcat

在启动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:

JavaWeb_第2张图片

http:默认的端口号为80  也就是说在URL中不给端口号就表示使用80端口,当然你也可以进行修改

如果你把端口号修改为80 浏览器直接输入http://localhost 就可以直接进入服务器

Web应用

静态网站:(漂亮的驱壳)

   如何发布静态的网址:

   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 应用程序的部署描述文件 可以在该文件中对应用进行配置

      比如配置某一个页面为主页……….

HTTP协议(重点)

协议:协议的甲方和乙方  客户端(浏览器)与服务器端

理解成双方的通信方式

  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_第3张图片

什么是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 只是一个地址

能通过映射来实现,如何映射?如下↓
JavaWeb_第4张图片

问题:之前咱们如何执行一个类的方法?

1.实例化类   2.通过对象调用类的方法

虽然servlet类是我们编写的,但是servlet中的大部分方法不由我们来调用,而是由服务器(TomCat)来调用,并且servlet的对象也不由我们创建,而是由服务器创建,而且一个servlet类型,服务器只创建一个实例对象,线程不安全,效率快。

 

Servlet的生命周期【出生---成长---入土】

实例化:服务器会在servlet第一次被访问的时候创建servlet

初始化:调用init方法

处理请求:当服务器每次接收请求时,都会去调用service处理

销毁:在服务武器关闭时,服务器会销毁servlet调用destroy()

 

在servlet里的对象

getServletConfig() 

servlet容器在初始化期间将信息传递给servlet的servlet配置对象【ServletConfig】

ServletConfig对象的作用?【读取servlet的配置文件  刚刚的映射我们去读了么?】

ServletConfig对象是由服务器创建的,然后传递给servlet的init()方法

可以再init方法中使用

String  getServletName() 获取servlet在web.xml中配置的名称,

就是指定的名称;【只返回自己的servlet-name

也就是说:一个servlet对象,对应一段web.xml中的servlet配置信息】

getInitParameter(Stringname)  用来获取web.xml里配置的初始化参

数值,更具名字来获取的。

getInitParameterNames()  用来获取在web.xml里配置的初始化参的

名称总合。

getServletContext()  获取ServletContext对象  后面单独说

-----------------------------------

ServletRequest和 ServletResponse

一个是请求对象,一个是响应对象,可以从ServletRequest对象中获

取请求的信息,可以从ServletResponse对象中完成响应,他们两都

成双成对的出现的

 

继承HttpServlet 实现查询功能的servlet

接收请求为什么

service(HttpServletRequestarg0, HttpServletResponse arg1)

也是可以的。

doGet()和doPost()

在httpServlet的

service(HttpServletRequest request,HttpServletResponse response)

方法会判断当前的请求到低是get/post,如果是get请求,那么会

去调用get请求,如果是…..。这说明我们以后真真编写的代码因该在

哪里? 以后只会重写doGet()和doPost()就行了。

Servlet细节

1.servlet与线程安全

因为一个类型的servlet只有一个实例对象,那么就有可能出现servlet同时被多个人请求,那么servlet就会存在线程安全问题。

所有我们不应该在servlet中创建全局变量,一般都是局部变量

因为可能会存在一个线程对这个成员变量进行操作,另一个线程对这个成员变量进行读取

一般的大佬行为:创建有状态的成员,该状态为只读

 

2.让服务器在启动的时候创建servlet

默认情况下,服务器会在某个servlet第一次收到请求的时候创建,也可以在web.xml中对servlet进行配置,使服务器在启动的时候创建servlet。

如何在web.xml中配置

元素中配置元素可以让服务器在启动的时候创建该servlet对象。

问题:多个元素中配置 如何创建?

元素的值必须是大于0的整数!可以配置不同的值来控制创建实例的顺序。


3.

的子元素,用来指定servlet的访问路径,即URL;它必须以”/”开头

1.可以在中配置多个

 <servlet-mapping>

    <servlet-name>ReServletservlet-name>

   <url-pattern>/address1url-pattern>

    <url-pattern>/address2url-pattern>

  servlet-mapping>

两个址都可以访问

2.可以再中使用通配符*如下

路径匹配 /user/*

如:/user/add.jsp   /user/servlce/update

扩展名匹配/*.jsp

如:/lsd.jsp    /123/456/789/lsd.jsp

 

匹配所有/*

4.servlet与反射

cn.niit.web.ReServlet

获取的只是一个字符串,凭什么能调用里面的方法?

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

一个项目只有一个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下

   userName

    tom

 

 

   passWord

   123456

 

如何在servlet里获取配置的全局信息

//读取全局的配置信息

JavaWeb_第5张图片

request 

请求的响应的流程?

JavaWeb_第6张图片

服务器处理请求的流程:

1服务器每次接收到请求,、都会为这个请求开辟一个新的线程

2服务器会把客户端的请求数据封装到request对象中,request就是请求数据的载体。

3服务器还会常见response对象,与客户端连接在一起,他可以用来给客户端发送响应

request和response,编码,路径

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

JavaWeb_第7张图片

便捷的重定向---以后我们就是这么写的

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

request是service方法的一个参数,类型为javax.servlet.http.HttpServletRequest.

在客户端发出的每个请求,服务器都会创建一个request对象

并把请求的数据封装到request对象中,然后调用service传递过去

说明在service方法中request对象可以读取请求的所有数据

 

回顾一下请求协议

请求行

请求头

空行

请求体(get没有请求体)

 

Request的功能可以分为一下几种

1.封装了请求头数据

2.封装了请求体数据,如果是get请求没有请求体【正文】

3.request是一个域对象,可以把它当做一个Map集合

4.request提供了请求的转发和请求的包含功能 

request获取请求头数据的方法有:

request获取请求相关的其他方法

JavaWeb_第8张图片

案例封IP

JavaWeb_第9张图片

Request获取请求的参数

最长见的客户端传递参数有 两种方式

1.浏览器地址栏输入网址,一定是get请求

2.超链接,一定是get请求

3.表单:可以是get请求也可以是Post请求 有method决定

get/post请求的区别

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和页面不带数据你就用重定向

 

编码的总结  【默认的编码都是iso-8859-1】

响应编码: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入门,cookie,HttpSession

什么是jsp

Jsp(java server  pages)是javaweb服务器端的动态资源,他与html的作用是相同的,显示数据和获取数据的【jsp可以通过变量来显示数据】

 

Jsp的作用

   Servlet:

   缺点:不适合设置html的响应体,因为需要大量的

   response.getWriter().print(“”);

   优点:动态资源,可以编程。

   Html:

   缺点:html是一个静态的页面,不能包含动态资源

   优点:可以不用输出标签,标签可以直接写。

   Jsp:

   优点:在原来的html基础上添加java脚本,构成jsp页面。

 

  Jsp和servlet的分工

  Jsp:作为请求的发起页面。例如:表单的提交,超链接的点击

     作为请求的结束页面。显示登录的结果,显示访问的网址

  Servlet:作为请求处理数据的环节

 

Jsp的组成

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的分工

JavaWeb_第10张图片

Jsp是特殊的servlet

JavaWeb_第11张图片

Jsp是特殊的servlet,当jsp页面第一次被访问的时候,tomcat会把jsp翻译成.java文件,然后再把java文件编译成.class文件,然后由服务器去创建class对象,最后调用_jspService(request response)

Servlet的创建:第一次接受请求服务器创建servlet对象,且同一类型的servlet只会创建一次。调用service方法(request response)

 

Jsp的注释

<%--  --%>不会被编译

Html的注释

不会再浏览器上显示,但是可以查看

什么是Cookie

【为什么再次登录的时候 用户名框会有你之前输入的账号

预览商品,为什么会有,你访问过得商品】

1.Cookie是HTTP协议的规范之一,它是服务器端和客户端之间传输的小数据。

首先是由服务器通过响应头把Cookie传输给客户端。

response.addHeader(“Set-Cookie”,”lsd-lsdd”);

response.addHeader(“Set-Cookie”,”lsx-lsxx”);

客户端会将Cookie保存起来

2.当客户端再次【不管是否从新打开浏览器】请求同一个服务器,客户端会在请求头中添加服务器保存在客户端的cookie。

JavaWeb_第12张图片

让服务知道  你就是刚刚访问我的那个人


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

JavaWeb_第13张图片

JavaWeb_第14张图片

Cookie的细节

Cookie的MaxAge

当服务器创建cookie对象后,可以调用setMaxAge方法来设置Cookie的最大生命。默认浏览器关闭就死掉。

MaxAge>0 表示cookie在客户端硬盘上的保存的最大时间 单位S

MaxAge<0  表示默认浏览器关闭就死掉

MaxAge==0 表示删除cookie

JavaWeb_第15张图片

【通过谷歌查看Cookie的生命  设置-内容设置-Cookie—查看Cookie】

HttpSession

JavaWeb_第16张图片

在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

Session的域方法

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,EL表达式

Jsp指令

Jsp的标签指令格式:<%@指令名  attr1=””  attr2=”” ..... %>

一般都会把jsp指令放在jsp文件的最上方。但这不是必须的。一个页面可以有0-N个指令

 

Page指令

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去继承某个类

 

指令include----静态包含

与request.Dispatcher的include()方法相似

request.Dispatcher的include()方法。包含和被包含是两个servlet,也就是两个.class。只是把响应的内容输出到页面。

JavaWeb_第17张图片

<%@include%>在jsp被编译成java时,合并成一个java文件,然后在生成class

作用:把页面分解,使用包含的方式合并在一起,这样一个页面中不变的部分就是一个独立的jsp.而我们只要处理变化的页面

 

指令taglib---导入标签库的

两个属性:

Prefix:指定标签库在本页面中的前缀,有我们自己取名字

Uri:指定标签库的位置

<%@ taglib prefix=“s” uri=”/struts-tags” %>

前缀的用法  

jsp的九大内置对象

在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动作标签【20个 】

这些jsp动作标签与html提供的标签有本质的区别 【html是由浏览器执行的】

动作标签是由tomcat[服务器]执行的,他与java代码一样,都是在服务器端执行。

转发!它与requestDispatcher的forward方法一样。一个在servlet中使用,一个在jsp中使用。

:包含!它与requestDispatcher的include方法一样。一个在servlet中使用,一个在jsp中使用。

JavaWeb_第18张图片

【<%@include%>和的区别】

:它作为forward和include的子标签用于转发和包含的参数传递

a.jsp

b.jsp

配置的补充

1.改了内部文件不重启服务 照样可以

 Conf/Context.xml

Tomcat内部会每隔一段时间自动刷新,仅限开发使用

有的时候会失常【离下一次刷新的时间还没到】

 

2.为什么一个请求一个jsp页面服务器不会当成servlet?

当它确认是jsp后怎么去翻译成Java文件的?

JavaBean【java组建】

JavaBean的规范;

1.必须要有一个默认的构造器

2.提供了get/set方法,如果只要get,那么这个属性是只读属性

3.属性:有get/set方法的成员,或者只有get/set方法

4.方法的名称满足一定的规范,那么他就是属性。Boolean类型的属性,他的读取方法可以is/get

 

内省

内省类--》Bean属性--》属性描述器--》属性的get/set对应的method—》反射

Jsp中与javaBean的相关标签【model1模型常用的标签  】

   //创建或查询Bean

  //设置Bean的属性

  //获取Bean的属性

EL表达式

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,param对象可以用来获取参数

等同于:request.getParameter()方法相同

6.paramValues:

Map,param对象可以用来获取参数

当一个参数对应多个值的时候。

等同于: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

  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. 地址  【他会在路径的前面自动加上项目名】

  如:  输出:/项目名/index.jsp

  子标签: 用来给url后面添加参数的

  如:

      

    

  输出   /项目名/indexjsp?name=lsd 

  Var:指定变量,一旦添加这个属性,那么url标签就不会输出,而是把生成的url保存到域中。

  Scope:他与var一起使用,用来指定保存url的域

 

5. 分支判断

  test :当test的值为true时,执行标签的内容;

  2}”>true执行的内容

 

6.:choose  类似if  else if  else if  else

 

  

     这是1号种子

     这是2号种子

     这是3号种子

     这是4号种子

     这是坏种子  

  

 

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设计模式

  MVC设计模式是所有的B/S项目的设计模式。把软件分成三个基本的部分

  模型(Model)  视图(View)  控制器(controller)

  可以对后期的维护/扩展起提供了方便。

 

控制器(controller)接收用户的请求,调用对应的方法,得到处理额结果,跳转对应的页面 (servlet)

  模型(Model)     编写的javaBean实现增删改查 (JDBC)

视图(View)      呈现数据(jsp)

控制器接收请求调用模型处理,根据处理的结果调用不同的视图来呈现给用户

 

JavaWEB与MVC

  经历了JspModel1一代,jspModel1二代,jspModel2三代

 

jspModel1第一代

  最早的模型:适合小型的文本项目,开发成本极低,服务器端只有jsp页面,所有的操作都在jsp页面中执行。连数据库的访问也是在页面中编写的。也就是说,所有的东西全部耦合在了一起。对以后的维护/扩展极为不利

JavaWeb_第19张图片

JspModel1第二代

  JspModel1的升级版本,把业务逻辑放到了javaBean中,而jsp页面负责显示,以及请求的调度,虽然第二代比第一代好,但是jsp做了过多的工作。Jsp中把视图和控制器的事耦合在了一起


JavaWeb_第20张图片

JspModel2第三代

  已经清楚的看得见MVC的设计模式了

Jsp:视图层;用来和用户打交道,负责接收用户的数据以及显示给用户的数据

Servlet:控制层;负责找到合适的模型对象来处理业务逻辑,跳转到合适的视图

JavaBean:模型层 完成具体的业务工作


Java经典的三层架构

它是由Javaweb提出的。

所谓的三层!

业务逻辑层(Business Logic) biz

数据访问层(Data Access ) dao

WEB层 包含jsp,servlet,等与Web相关的内容  


JavaWeb_第21张图片

javaWeb监听器

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>

过滤器(Filter)

什么是过滤器:

过滤器是javaWeb的三大组建之一。他与servler非常的相似,不过他是用来拦截请求的,而不是用来处理请求的。

当用户请求某个servlet时,会先执行部署在这个请求上的Filter,如果Filter‘放行’,那么会继续执行用户请求的servlet,如果Filter不‘放行’,那么就不会执行用户请求的servlet。

JavaWeb_第22张图片

它会在一组资源【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()
获取Filter的配置名称,与元素对应

 String

getInitParameter(String name)
获取filter的初始化配置信息,与元素对应

 Enumeration

getInitParameterNames()
获取所有的初始化参数的名称

 ServletContext

getServletContext()
获取ServletContext对象

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

  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是否为状态响应码是否为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是否为状态响应码是否为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是否为状态响应码是否为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是否为状态响应码是否为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的一套封装   

牛逼的servlet

我们想这么来架构:

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”;

}

BaseServlet模板



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();
		}
	}

JDBC

事务的4大特性(ACID)

四大特性:

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?

DBCP是Apache提供的一款开源免费的数据库连接池。

DBCP的使用(DBCP的池类BasicDataSource)

JavaWeb_第23张图片

C3P0

  C3p0也是开源免费的连接池,c3p0被许多人看好。

 

C3P0的使用(C3P0的池类是:ComboPooledDataSource)

配置文件要求:

1.文件名必须叫:c3p0-config.xml

2.文件位置:src同目录下的资源文件夹内

【见jar包里的配置】

 

通过配置文件 在类里获取Connection对象

JavaWeb_第24张图片

最终的JDBC

工具包的修改【连接的方式】

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 listStudent() throws SQLException{

       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 mapStudent(String sname) throws SQLException{

       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 List> MaplistStudent() throws 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());

    }





你可能感兴趣的:(后端)