Servlet/listener/filter应用大全

服务器servlet/listener/filter

11 http/tomcat

 - http协议版本 使用最广泛的是1.1的版本。  它是一种请求 - 响应  模型的协议。

 1.0请求 - 响应完毕后,连接关闭  , 如果还想接着请求,必须得重新连接

 1.1 请求 - 响应完毕后,连接未关闭 ,还可以继续发起请求

Get请求和post请求的区别   如果action 都写成 action=”#”  post请求 不提交请求   get请求 action=”#” 提交请求 按照现在的路径主路径去掉后面的参数  拼接上自己的参数 重新请求

1 请求的方式Get

请求时长度有3个条件决定,浏览器/服务器/操作系统

1 请求行:

GET /LoginDemo/login?username=admin&password=123456 HTTP/1.1 表示使用Get请求 , 表示请求什么路径地址  ,表示使用什么版本的协议

获取请求头的方式,   request.getMethod();  获取当前请求头是get /post

2 请求头 :

Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*

Referer: http://localhost:8080/LoginDemo/login.html

Accept-Language: zh-CN

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

Accept-Encoding: gzip, deflate

Host: localhost:8080

Connection: Keep-Alive

1. Accept : 声明客户端可以接收什么类型的数据

2. Referer : 表示请求从哪里过来的

3. Accept-Language  : 表示客户端支持的语言

4. User-Agent  : 表示客户端的信息

5. Accept-Encoding  : 表示客户端支持的压缩格式

6. Host : 表示主机地址

7. Connection  : 表示连接状态。

3 请求体:

GET方式的请求,没有请求体。 因为数据都是拼接到了地址上去了。

4 响应行

响应行 HTTP/1.1 200 OK  表示服务器也支持1.1的版本协议 , 对这次请求处理的状态码是200 ,OK

5 响应头

Server: Apache-Coyote/1.1  : 服务器版本

Content-Length: 75  : 返回的数据长度 用来和请求时候数据的长度做校验 确认数据是否丢失

Date: Sun, 21 May 2017 07:09:28 GMT  : 响应时间

6 响应体

login failed ~ please use  username : itheima , password : 10086 try again~

2 POST请求

1请求行

POST /LoginDemo/login HTTP/1.1   意思和get请求的意思一样,只不过这里的地址再也不跟数据了。

2请求头

Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*

Referer: http://localhost:8080/LoginDemo/login.html

Accept-Language: zh-CN

User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip, deflate

Host: localhost:8080

Content-Length: 29

Connection: Keep-Alive

Cache-Control: no-cache

Content-Type :  其实就是说明提交上去的数据是什么类型数据 。  是一个经过url编码的form表单数据

Content-Length :提交的数据长度

Cache-Control : 表示再次请求的时候,是否读缓存。

3请求体

username=itheima&password=123

4响应行 响应头 响应体

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Content-Length: 75

Date: Sun, 21 May 2017 07:32:12 GMT

login failed ~ please use  username : itheima , password : 10086 try again~

3 GET 和 POST方式的区别

- GET

  1. 它的地址会带上数据,  http://www.itheima.com?name=aa&age=18

  2. 能够带的数据有限制。

  3. 由于数据会拼接到地址栏上面,所以不安全

- POST

  1. 它的地址不带数据,就是很干净的地址而已。

  2. 带的数据没有限制。 (因为数据是以流的方式写过去。)

  3. 由于数据没有拼接,所以数据比较安全

  4. 额外多两个头字段  Content-Type  Content-Length.  

4 软件架构

- C/S架构

 client【客户端】 / server【服务器端】  如: QQ 、微信、 迅雷 、 LOL 必须得安装一个客户端,才能和服务器对接。

    优点: 1.  视觉比较炫酷 、 用户体验好 2.  一部分资源|数据放在了本地 、减轻服务器压力

    缺点:   1. 占用本地硬盘空间   2. 更新比较困难、 服务器只要一更新,客户端也得跟着更新 3. 平台、系统环境的限制

- B/S架构

 browser【浏览器】 / server【服务器端】 如:  网页游戏 、 网页QQ 、通过浏览器来和服务器对接

    优点: 1. 不用安装 、只要有浏览器就行。 2. 一般也不用做更新。 3. 不受平台限制 、 不占用本地的空间。

5常用的服务器软件

1.Tomcat  : Apache 提供的一个免费小型服务器软件 , 支持JSP/Servlet 规范

2.WebLogic  : Bea公司提供的收费大型服务器软件 , 支持EE的所有规范

3.WebSphere : IBM公司收费大型服务器软件 ,  支持EE的所有规范

4.JBoss  :  一个基于J2EE开放源码的服务器软件 核心不支持 JSP/Servlet ,一般与tomcat 或者 jetty配合使用

6 tomcat   

1.开启tomcat   解压 . 进入tomcat /bin  , 点击startup.bat

2.配置文件    如果见到一闪而过的情形, 那么打开dos窗口,然后拖拽startup.bat进去后,回车,即有提示,一般都是没有配置环境变量  

JAVA_HOME    CATALINA_HOME : 其实就是tomcat的根目录路径,还有JRE_HOME(就是jre包)

配置好之后,在执行即可

3.访问方式    打开浏览器,然后输入地址  http://localhost:8080

3 tomcat和jdk和eclipse 遇到的一些问题

1 在path 中配置和 %java_home%/bin   在java_home中配置好 jdk以后就不用整了   默认的tomcat要用到jdk

2 对于不同版本的tomcat 配置不一样   有的要配置catalina_home

4如果tomcat端口被占用,解决办法

1> 修改端口 F:\apache-tomcat-7.0.52\conf\server.xml 第70行:  <Connector port="8081"/>

2> 关闭端口号对应的进程:cmd-->netstat -ano -->找到pid-->任务管理器-->显示pid-->关闭进程

WEB-INF : 注意:固定写法。此目录下的文件不能被外部直接访问。

classes:我们编写的程序代码。.class文件

lib :  应用需要用的jar文件

web.xml  : 应用的配置信息

7虚拟路径 2种方法

1. 在conf/server.xml   host 节点 docBase 真实的路径path : 虚拟路径<Context docBase="D:\aa\"  path="/cc"/>http://localhost:8080/cc/aa.txt

2. 在 conf/catalina/localhost a. 新建一个文件 ,必须是 xml  heima.xmlb. 文件的内容是 : <Context docBase="D:\aa\"  />c, 文件名就是我们的path虚拟路径 http://localhost:8080/heima/aa.txt

1当在Eclipse下启动tomcat的时候    浏览器默认找的是wtpwebapps文件夹   这个是eclipse自己建的文件夹

2当你从外部开启Eclipse的时候   浏览器默认是找webapps项目  这个是tomcat建的项目  会自动跑这个项目

12 Servlet

servlet 是运行在Web服务器中的小型 Java 程序(即:服务器端的小应用程序).servlet 通常通过HTTP(超文本传输协议)接收和响应来自Web客户端的请求。 Servlet 是 javaWeb的三大组件之一(Servlet ,filter,listener) 且最重要

Servlet家族结构图 http://blog.csdn.net/shuaishuai3409/article/details/52667401

servlet是服务器端(tomcat)运行的一段Java程序(java接口),通过http协议,负责接收和响应web客户端(浏览器)的请求。

先附上servlet家族图谱。

1编写一个servlet程序:

a、写一个java类,实现servlet接口

b、修改web.xml文件,给servlet提供一个可访问的URI地址

c、部署应用到tomcat服务器

D、测试:http://locahost:8080/day08_servlet/demo1

执行过程

2 Servlet生命周期(重要)

实例化-->初始化-->服务->销毁

出生:(实例化-->初始化)第一次访问Servlet就出生(默认情况下)doGet  doPost 不是生命周期方法,因为这个不是必要的方法

- init 【创建对象】servlet在初始化的时候执行。 只会执行一次

活着:(服务)应用活着,servlet就活着

死亡:(销毁)应用卸载了servlet就销毁。正常关闭服务器 | 从服务器里面移除托管。

Servlet启动时创建

小知识:如何让servlet在服务器启动时就创建。

3 Servlet的三种创建方式

Servlet --> GenericServlet --> HttpServlet  (自己写都是继承HttpServlet)

曾祖父     爷爷        爸爸     孙子

1、实现javax.servlet.Servlet接口(参见:编写一个servlet程序:)

2、继承javax.servet.GenericServlet类(适配器模式)(这个类已经实现了Servlet接口了)

3、继承javax.servlet.http.HttpServlet类(模板方法设计模式)(开发中常用方式)

小技巧:使生成的servlet更清新一些

找到:MyEclipse\Common\plugins目录

把com.genuitec.eclipse.wizards_9.0.0.me201108091322.jar复制到上面目录

HttpServlet 运行顺序:

1. 收到浏览器发送过来的请求, 会执行 HttpServlet  的service方法,执行生命周期的所有方法,然后在该方法里面对请求方式进行判断

真正顺序应该是这样: 每一次servlet收到请求,service来处理请求,但是我们自己的类没有这个service方法,所以会去找父类(HttpServlet)的service方法  myServlet继承了 HttpServlet  系统默认创建的是 Servlet servlet= new MyServlet; 自己的MyServlet里面没有这个方法 就去父类的里面找 service方法  父类执行了service方法 又执行doGet  或者doPost方法  现在我们重写了这两个方法 就执行我们的了 继承与多态

运行路线如下:

1. 浏览器地址输入: http://localhost:8080/ServletDemo02/demo

2. 在web.xml里面找到了ServletDemo这个类,

3. 调用ServletDemo这个类中的service方法。

4. 找父类HttpServlet 的 service(ServletRequest req, ServletResponse res)

5. 调用父类HttpServlet 的 service(HttpServletRequest req, HttpServletResponse resp)

6. 在方法里面判断请求方式, 然后调用doGet 或者 doPost

7. 虽然父类声明了doGet  和 的哦Post ,但是我们的子类重写了这个两个方法,所以最终就来到了子类的doGet 或者 doPost

8. 继而执行 doGet 方法 或者 doPost方法

4 Servet多种映射配置:

servet映射细节1:

servet映射细节2: 通配符* 代表任意字符串

url-pattern: *.do  以*.字符串的请求都可以访问 注:不要加/

url-pattern: /*  任意字符串都可以访问

url-pattern: /action/* 以/action开头的请求都可以访问

匹配规则:优先级:从高到低 绝对匹配-->  /开头匹配 --> 扩展名方式匹配

如果url-pattern的值是/,表示执行默认映射。所有资源都是servlet

4 Servlet的线程安全 单实例:每次访问多线程 解决线程安全问题的最佳办法,不要写全局变量,而写局部变量。

5 ServletConfig 获取配置信息 2

1 ServletConfig的对象的创建

1使用初始化方法 getservletConfig.此对象由服务器创建public void init(ServletConfig arg0) throws ServletException { } 这个方法是httpservlet的方法

2通过this获取这是多态 调用父类的方法得到的config this.getInitParameter(“encoding”)  这个是父类GenericServlet 创建的  这是用的父类的方法

3 通过使用父类的方法servletConfig config= this.getSetvletConfig()   这个通过多态 本类对象调用父类的方法得到

2 config获取 全局参数

//1. 获取servletConfig对象。ServletConfig config = this.getServletConfig();  用来获取xml里面的参数

 <init-param>

    <param-name>name</param-name>

    <param-value>xiaoming</param-value>

  </init-param>

//2. 获取servlet名称String servletname = config.getServletName();

//3  获取初始化参数 只取一个String heima = config.getInitParameter("name");

//4  获取所有的参数名。 接着遍历。 取到所有的name 这是一个枚举集合

Enumeration<String> initParameterNames = config.getInitParameterNames();

//遍历所有的name

while (initParameterNames.hasMoreElements()) {

//得到每一个name

String na = (String) initParameterNames.nextElement();

//根据name 获取到每一个name的value值。

String value = config.getInitParameter(na);

System.out.println(na + " ====  "+ value); }

作用2:可以获得ServletContext对象    ServletContext  context = getServletConfig().getServletContext();

6 Servlet使用步骤

1先用servlet的3种方法创建一个Servlet

2 配置servlet

3 获取配置文件信息

Web 资源

静态资源 index.html;  --- localhost:8080/项目名/index.html   静态资源就是直接访问html代码

动态资源  ServletDemo --- localhost:8080/项目名/ServletDemo 动态资源就是通过html网页再提交到servlet   或者直接访问servlet

* 1. 写一个类,实现Servlet接口。

* 2. 配置Servlet  WEB_INF/web.xml

3通过配置文件映射的路径 直接提交到 动态的java代码

13 servletContext/Response/request

1 servletContext 3

它是servlet的上下文,在服务器启动的时候为托管每一个项目生成一个servletCotnext实例, 注意:有且只有一个。 而且每一个项目都有一个。 

- 作用1. 存取数据  2. 获取全局参数   3. 读取项目资源    context与一般的

1 存|取数据 2

1.ServletContext context = getServletContext(); 得到对象

setAttribute(name ,value)设置数据 getAttribute(name)得到数据

//获取ServletCotnext的实例对象 服务器为每一个应用只创建一个它的实例对象。

ServletContext context = getServletContext();

//1.设置一个属性,其实就是存值。  参数一 ,有点像map的key , 参数二 ,有点像map的value

context.setAttribute("name", "telangpu");

//2.取值。和存值的name要一致,否则取不到值

String name = (String) context.getAttribute("name");

在AServlet 存值, 然后跑到B Servlet 去取值,也可以取出来,因为他们的ServletContext的实例对象是同一个。

 Enumeration<String> names1 = context.getAttributeNames();

//3删除值void rmoveAttribute(String name);//根据name去移除数据

2 获取全局参数 2

1. 声明参数 , web.xml 里面声明

 <context-param> <param-name>cname</param-name> <param-value>cvalue</param-value>  </context-param>

2. 获取参数

1获取单个名称的值。

String servletName = context.getInitParameter("servletname");

String cname = context.getInitParameter("cname");

2获取所有的名称  ---> 进行遍历

Enumeration<String> names2 = context.getInitParameterNames();

while(names2.hasMoreElements()){

     String names3 = names2.nextElement();

     String haha4 = context.getInitParameter(names3); }

3 获取项目资源 3

getRealPath() 这个只是拼接路径 作用小    getResourceAsStream()这个里面写是通过原有的路径加上现在的路径  

1据资源名称得到资源的绝对路径.  2自己确定相差多少路径    3填写到第二个方法中缺少的路径

//1. 创建一个properties对象 Properties properties = new Properties();

//第一种方法: 获取path路径:  然后自己转化成输入流  这是链接的拼接

String path = getServletContext().getRealPath("/WEB-INF/classes/aa.properties");

InputStream  is = new FileInputStream(path);

//第二种方法:直接获取文件转成的输入流对象 把资源转成流对象

//InputStream is = getServletContext().getResourceAsStream("/WEB-INF/classes/aa.properties");

properties.load(is);

//3. 读里面的信息

String name = properties.getProperty("name");

String address = properties.getProperty("address");

第三种方法 使用类加载器获取项目资源

// 1. 创建一个properties对象Properties properties = new Properties();

//根据当前对象,取到字节码,然后取到类加载器。 是去找classes文件夹//SerlvetContext找的时候,去哪个路径找??项目发布的根目录。

InputStream is = this.getClass().getClassLoader().getResourceAsStream("aa.properties");

properties.load(is);

// 3. 读里面的信息String name = properties.getProperty("name"); String address = properties.getProperty("address");

ServletContext 找的路径是项目发布到tomcat的项目根目录

ClassLoader找的路径是classes文件夹目录

4 实现Servlet的转发

 RequestDispatcher  getRequestDispatcher(String path) ;//参数表示要跳转到哪去

5 作用范围

> 整个项目,因为一个项目只有一个ServletContext的实例

*  生命周期 何时创建1.服务器启动(项目本来) 2.发布项目的时候

    何时销毁 1. 关闭服务器  2.  移除项目

通常把这种能够存值  和 取值, 且有一定的作用范围的对象称之为域对象 。 也可以叫做作用域。

1 Response

* Response 是什么? Exemple    1表单访问打印是多少位访问案例     2手动下载和tomcat自动下载

服务器端用户给客户端写数据的对象,也就是服务器要告诉客户端,请求到底处理得怎么样 ,结果要输出出来给客户端,就是靠这个response对象。

1获取请求值   res.getInitparameter(“”)

1 response作用 3

   //1.设置行 response.setStatus(200); //response.setStatus(404, "zhao bu dao ~~");设置响应状态码

   //2.设置头 sendRedirect(String location) 请求重定向

response.setHeader("Content-Length", "1000");  设置响应头信息

response.addHeader()

   //3. 设置体

   //字符流 response.getWriter().write("hi response ~~~");    write里面能够解析html代码   里面可以方标签   

字符流里面只能写 String char[]数组  这个只能写文本

   //字节流 //response.getOutputStream().write(b);这个可以读byte[] 读byte里面的数组 读int类型 的编码 是上面输入流读进来的数据 放到这两个里面

区别 虽然response对象的getOutputStream()和getWriter()方法都可以发送响应消息体,但是,它们之间互相排斥,不可同时使用,否则会 发生 IllegalStateException异常    

2 response中文乱码问题 2

//因为默认写出去的时候,使用的编码是 : ISO-8859-1

1写出去

1. 解法一 :

//1. 设置写出去的时候,告诉tomcat服务器使用UTF-8写出去。response.setCharacterEncoding("utf-8");

//2. 配合上面使用,告诉浏览器,我们发送过来是什么数据,然后请他用什么编码去看。 那么浏览器就会自动选择这种编码去看。

//告诉浏览器,我们服务器送过来的是文本类型的数据,其实就是一个html网页, 请它用utf-8编码来看。

response.setHeader("Content-Type", "text/html;charset=utf-8");

2. 解法二:

//这一行代码包含了上面两行代码的意思。response.setContentType("text/html;charset=UTF-8");

3.解法三  告诉浏览器这是一个附件

String filename = String.format("orders_%d.xls", getId());  这是文件的名字

//告诉浏览器,有个名称为XXX附件,下载文件, ISO-8859-1转码,否则下载下来的文件名为乱码

res.setHeader("Content-Disposition", "attachment;filename=" + filename);

对于写出去的文件名字是中文格式.需要修改

3. 写出去的时候,也需要对我们的文件名进行编码。

这得分浏览器类型。 如果是Firefox 浏览器,使用的是Base64的编码处理手法,

如果是ie 或者谷歌, 那么使用的是URLEncode 处理手法。

String userAgent  = request.getHeader("User-Agent");  //获取是什么类型的浏览器  是火狐还是ie\google浏览器

if(userAgent.contains("Firefox")){

fileName = base64EncodeFileName(fileName);  //另一个类里面有这个写的专门用于火狐编码的文件

}else{

//IE \ Google 浏览器

fileName = URLEncoder.encode(fileName, "UTF-8");   //这是java的一个类对文件名称文件 编码的文件

}

System.out.println("写出去的时候,文件名是:"+fileName);

//在页面上有提示用户,到底是保存文件还是直接打开文件。  如果没有这个,那么就是直接打开了。

response.setHeader("Content-Disposition", "attachment; filename="+fileName);

下面是另一个类专门对火狐进行编码的代码

public static String base64EncodeFileName(String fileName) {

BASE64Encoder base64Encoder = new BASE64Encoder();

try {

return "=?UTF-8?B?"

+ new String(base64Encoder.encode(fileName

.getBytes("UTF-8"))) + "?=";

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

 

2读进来

1 解决post方式编码

request.setCharacterEncoding("UTF-8"); //告诉服务器客户端什么编码编译出来,只能处理post请求方式

上面的只是告诉tomcat用utf-8编译出来客户端的数据    一般浏览器提交过来的都是utf-8

2 解决get方式编码  把读进来的name重新用iso-8859-1返回去 然后再用UTF-8读取

String name = new String(name.getBytes(“iso-8859-1”),”UTF-8”);l

getBytes()  使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。然后再用Utf-8编译出来

//告知客户端不缓存

response.setHeader("pragma", "no-cache");

response.setHeader("cache-control", "no-cache");

response.setDateHeader("expires", 0);

3 点击下载-案例

1 Tomcat 写个超链接 当点击超链接的时候,超链接的路径是tomcat的路径.形式要是文件的类型写的是英文名能正常访问,如果文件名写的是文字访问不了

2 自己写 点超链接提交到servlet自己写下载 用response.getOutputStream   写到浏览器上

Html提交的时候带自己写的参数 get请求

<a href=”servlet01?filename=aa.txt”> aa.txt<a/>    在地址栏上直接拼接上?key=value 的形式   这就是和Get请求时候提交数据一样

步骤

//1. 获取到了要下载的文件名称。

String fileName = request.getParameter("filename");

2//接下来要做的工作,就是把这个文件写出去。 response.getOutputStream()  还欠缺输入流。 inputStream

//获取输入流

InputStream is = getServletContext().getResourceAsStream("resource/"+fileName);

3//获取输出流

ServletOutputStream os = response.getOutputStream();

byte[] buffer = new byte[1024];

int len = 0 ;

while( (len = is.read(buffer)) != -1){

os.write(buffer, 0, len);

} os.close(); is.close();

4保存提醒的功能

response.setHeader("Content-Disposition", "attachment; filename="+fileName);    这个是根据response里面的API查找的  后面拼接的是文件的路径  是那个文件这样打开保存

5验证码的校验

<div class="col-sm-3" >

      <!-- <img src="./image/captcha.jhtml"/>-->

      <img src="Validate" οnclick="change(this)"/>

    </div>

    <script type="text/javascript">

function change(img){

img.src="Validate?aa="+new Date();

}

</script>

3 request

1 请求行  

Get  http://localhost:8080/day09/servlet/req1?username=zs  http/1.1

1 getMethod(); 获得请求方式

2 getRequestURL();返回客户端发出请求时的完整URL。

3 getRequestURI(); 返回请求行中的资源名部分。

4 getContextPath(); 当前应用的虚拟目录 /day09_01_request

5 getQueryString() ; 返回请求行中的参数部分。

2 请求消息头

1 * String   getHeader(String name)  根据头名称得到头信息值

2 Enumeration   getHeaders(String name)  根据头名称得到相同名称头信息值

3 Enumeration   getHeaderNames()  得到所有头信息name

3 请求正文5

与获取表单数据相关的方法

<input type="text" name="username" />

1 getParameter(name) 根据表单中name属性的名,获取value属性的值方法

2 getParameterValues(String name)可以拿多个同名的参数,封装到集合

3 getParameterNames() 得到表单提交的所有name的方法

//2. 获取所有的头名称  封装到枚举集合里面

Enumeration<String> headerNames = request.getHeaderNames();

//遍历所有的头  

while (headerNames.hasMoreElements()) {

String name = (String) headerNames.nextElement();  //取出来每个值

String value = request.getHeader(name);

System.out.println(name +" = "+ value);

}

4 getParameterMap 到表单提交的所有值的方法 封装到Map集合中  //做框架用,非常实用

5 getInputStream  以字节流的方式得到所有表单数据   字符流getRead

4 存值取值 2

1 void setAttribute(String name, Object value);

2 Object getAttribute(String name);

3 Void removeAttribute(String name);

Request与servletConfig 的区别

与操作非表单数据相关的方法(request也是一个域对象)   request里面有个成员 hashMap集合 每次请求都会创建一个request对象 每次对象都会创建一个Hashmap集合  所有每个request都有一个集合 每次都是取自己request里面的键值对 随着请求创建 随着响应销毁

Config里面

Tomcat里面默认有个 request 设置的属性 每次再写属性的时候 都是覆盖了那个属性

6 设置变量区别 1成员变量--2 servletConfig----3 servletContext---4 request 区别

1 设置成员变量 只能在本类中使用,在其他类不能使用

2 servletConfig 这是项目已启动

4 reruest原因是 :来一次请求就会生成一个全新的request对象,所以第二次过来的请求就取不到以前第一次请求对象设置的值。一次请求里面,也就是服务器对这个请求做出了响应之后,就没法取值了。跳转到下一个servlet 不是响应,这时候在下个servlet也能取到这个值 这时候都是一个request

4个的权限不一样 更好利用

4 请求转发/重定向/html--servlet  3个

1重定向特点:1请求次数2次,  2地址显示:第二次的地址;  3 request存储无法使用;效率低;   4 web任意资源位置都能跳

response.sendRedirect("other.html");

2请求转发:特点: 1请求次数1次;  2地址显示发起请求的地址  3request存值可以使用   4效率相对高  5只能跳转服务器内部资源,因为是服务器内 部帮我们跳转 request.getRequestDispatcher("other.html").forward(request, response);

区别:请求转发是服务器帮我们在后台进行请求转发,还是一次请求,后面带着这次请求的参数forward ,服务器帮我们转发,第二次的页面上的地址不变化. 重定向是我们命令浏览器再次进行访问的地址.重定向2次跳转 地址栏的地址还是原来的地址

重定向,请求转发servlet------到servlet    servlet------到浏览器

3在网页向页面跳转  页面向servlet跳转  每次请求都可以在请求的后面加 ?aa=3  进行传值 action=”code?aa=3”

location.href=”01.html” 跳转到html页面   href  <img src=”code” />    <from action=”code” >  只要是链接的形式都能提交访问servlet

Location.href=”servlet”; 跳转到servlet 动态的   这个是servlet映射的名称

RequestDispatcher getRequestDispatcher(String path)

*** forward(ServletRequest request, ServletResponse response) //转发的方法

include(ServletRequest request, ServletResponse response) //请求包含

4重定向   response.setStatus(302);response.setHeader(”location”,/servlet/servlet2)  这是重定向的另一种写法

可以跳到servlet

重定向地址栏的值会发生变化,当多次重定向servlet的时候  会显示最后那个servlet的内容   因为:重定向地址栏会改变,同时输出servlet3中的值

访问jsp的4种方式

 

1请求转发  2重定向   3including包含   4错误跳转

5 相对/绝对路径:

请求转发 : 相对的是当前的请求路径 。 谁发起的这个请求, 就是谁的路径为当前请求路径

login.html : http://localhost:8080/PathDemo/login.html

当前路径就是 : http://localhost:8080/PathDemo/

总路径  =  当前路径  + 参数

index.html =   http://localhost:8080/PathDemo/index.html

request.getRequestDispatcher(index.html").forward(request, response);

重定向 :

重定向的路径写法也是相对当前的请求路径,和请求转发是一样的写法。

发起请求 : login.html --- http://localhost:8080/PathDemo/login.html

当前的路径: http://localhost:8080/PathDemo/

总路径 = 当前路径 + 参数

index.html = http://localhost:8080/PathDemo/index.html

response.sendRedirect("index.html");

绝对路径 :

请求转发 :前面是接上项目的根目录

重定向  : 前面是接上 tomato的根目录

相对路径:

请求转发 :前面接的是当前请求路径

重定向 :  前面接的是当前请求路径。

网页跳转form action

如果不加 / 前面接的是当前请求路径<br>

如果加 / 前面接上 服务器的根路径 -->

当前路径:

总结:当前路径怎么看的呢? 其实就是看谁执行的这次请求, 谁执行的这次跳转的动作,那么当前的请求地址路径,就是这个人的地址路径。 如果是页面发起的请求,就是页面的路径为当前路径,如果是servlet发起的请求,那么servlet的地址路径就是当前路径。

在 jsp     建议用绝对路径${pageContext.request.contextPath}+.... 获取当前项目的路径

6 BeanUtile使用步骤

//3. 封装数据

//注册自己的转化器

ConvertUtils.register(new MyDateConverter(), Date.class);

//开始封装数据

BeanUtils.populate(user, parameterMap);

user.setUid(UUIDUtils.getUUID());

System.out.println("user="+user.toString());

Dbutils  bean的字段 和  数据库表的列名一致   Beanutils bean的字段 和 html页面提交过来的name属性样。

14 Cookie/session 会话

1 Cookie

> 小饼干 , 它其实就是保存在我们客户端上的一小份数据,以后执行请求就会自动带着这个cookie过去给服务器。

2 什么是会话

> 其实就是从我们打开浏览器开始访问,到关闭浏览器,那么这其中做的一系列操作,都可以称之为一次会话。

3 为什么要有cookie?

> 原因是Http协议是无状态协议。 服务器有时候需要知道发起这次请求的客户端是否是以前的某一次来访的客户端,以便做出更精确服务。 这时候就需要使用到cookie了。

1 cookie对象 1

能创建多个cookie 不超过300

    Cookie cookie02 = new Cookie("name","telangpu");

     response.addCookie(cookie);  //给客户端返回cookie。

2 获取cookie

   Cookie[] cookies = request.getCookies(); //1. 获取客户端带过来的所有cookie  Cookie: name=aobama; address=usa

    if(cookies != null){    //第一次过来访问, 是没有cookie的

    System.out.println("已经不是第一次来了, 有cookie");

    for (Cookie cookie : cookies) {

    String name = cookie.getName();

    String value = cookie.getValue();   

    }

    }

可以直接在js 页面取cookie

<script type="text/javascript">

οnlοad=function(){

var s="${cookie.savename.value }";

s=decodeURI(s);

//将解码后的用户名付给username的文本框

document.getElementsByName("username")[0].value=s;

}

</script>

例如下面的也一样

Cookie cookieRemember = new Cookie("rememberUsername", lisi)

取name值:${cookie.rememberUsername.name  }

取value值:${cookie.rememberUsername.value  }

initParam  : 全局配置参数

pageContext : pageContext对象

3 Cookie的设置 3

* cookie的类型

  1. 临时性cookie 没有针对cookie做任何设置,那么只要关闭了浏览器,那么就会删除cookie。

  2. 持久性cookie 会保存到磁盘中,在一定的范围内都有效。

 Cookie cookie = new Cookie("password","admin123");  

1 cookie.setMaxAge(60*60*24 *7); //设置有效期7天。如果设置的是 0 表示要删除cookie, 立即删除 , 如果是 -1 ,那么是关闭浏览器后删除

2 cookie.setDomain(".taobao.com");   //设置cookie跨域名共享。 domain 域名.   taobao tmall

3 cookie.setPath("/"); //设置当前服务器里面的跨项目共享

4 Cookie的使用步骤

1创建cookie对象, 这个是有参构造,只能存储两个字符串 key  value的形式

2响应response存储cookie对象到客户端   cookie都是以对象的形式存储的

3客户端有了cookie对象以后才能发送请求到 服务器

4服务器端取Cookie对象 Cookie[] cookies = request.getCookies(); String name = cookie.getName(); String value = cookie.getValue();

Cookie小知识

1  //给客户端返回cookie。 add多少次,就会有多少个 Set-Cookie 头

2 当存储的两个cookie对象的key值是一样的时候在客户端能收到两个cookie对象 但是服务器端只能取到后面一个cookie的值  相当于覆盖前面的值 Cookie cookie1 = new Cookie("name1","user"); Cookie cookie3 = new Cookie("name1","user1");   当这时候要是设置的cookie1.setmaxAge(60*60) 因为直接被cookie2取代了  设置的就没用了   重新打开浏览器  这时候还是保存的cookie3的值 第一次还是没有cookie的

3 设置有效时间  应该在响应cookie的时候设置

这是存储在客户端的,每次都要来回带  才能在客户端直到数据

2 Session操作

1 Session操作

1 Cookie 1数据存放在客户端 2数据不安全3减轻服务器压力, 用户磁盘占用比较多。 4 存放的数据有限

2 session 1数据存放在服务器端 2数据相对比较安全。3服务器压力大一点。4存放的数据 依赖服务器的内存空间. 基于|依赖cookie的一种会话技术。

###Session的简单使用

3能创建多个Session

1. 获取 sessionHttpSession session  =  request.getSession()

2. 存值 session.setAttribute(name ,value);

3. 取值 session.getAttribute(name);

4. 移除值 session.removeAttribute(name);

5. 让session失效 作废 session.invalidate();

6. 获取id值 session.getId() . > session的id值就是这一块内存空间的唯一标识符。

 2> session中除了 4个操作 map的方法之外,还有哪些方法.  

        long getCreationTime()   获得创建时间  

        String getId()    获得sessionID  

String sessionId = request.getRequestedSessionId();   用request获取Id

        long getLastAccessedTime()   获得最后一次访问时间  

        int  getMaxInactiveInterval()  获得session的寿命  

        void setMaxInactiveInterval(int interval)   设置session的过期时间   

        void invalidate()   让session立即失效  

        boolean isNew()    

    3> 关于设置session的最大有效时间  

        默认是30分钟. ==> 在tomcat的web.xml中 <session-config> 配置的.  

        如何修改session的过期时间?  

            1.修改在tomcat的web.xml中 <session-config> ==> 影响服务器中的所有项目  

            2.在项目的web.xml中 加入<session-config> 配置.==> 影响的是当前项目  

            3.通过setMaxInactiveInterval(int interval)方法设置.==> 当前操作的session  

              

    4>(了解内容)URL重写  

        如果浏览器 禁用cookie功能不能保存任何cookie.那么session技术要是用 cookie来保存sessionID. 没有cookie怎么保存?  

            使用url重写解决该问题.  

            将页面中所有的连接 末尾全都加上 cookieid的参数. 这样用户点击连接访问网站,通过url把SeesionID带到了服务器.这样就解决了.  

            但是 互联网行业没有这么干的.  

2 Session的作用范围 & 生命周期

* 作用范围 > sesison 作用范围:  一次会话范围内有效。(这个和cookie有区别,cookie可以设置保存时间,这个你要想用长时间多次一个Session,就只能得到这次的Id,  然后用这次Id的session   重新使用session)

* 生命周期

> 何时创建 第一次调用request.getSession()就创建。 访问jsp页面默认就 创建ssection对象就创建了  因为这是一次会话 都是一个session对象,后面关了浏览器就不是这个session的Id了 是另一个session对象

> 何时销毁 关闭服务器 (非正常关闭 : 销毁 , 正常关闭 : 序列化(钝化))

  session超时了。默认30分钟。 从最后一次请求开始计时。

   调用invalidate . 让空间失效、作废

3 Session的背后细节

//这里获取session的机制是这样的。  Session是依赖于cookie的对象 每次都要cookie带来值用来确定是否要重新创建新的Session

// 第一次来访问,/*那么session都没有创建,并且咱们的请求对象里面也不带任何的cookie过来。

那么这个时候会在内存中给你创建一个新的session区域,并且把这个session的id值给我们的浏览器返回。

如果是第二次访问,那么浏览器会把之前的那个cookie给带过来, 服务器收到了cookie,里面有我们上一次给的

sessionid 值, 那么这个时候再调用request.getSesion() , 它先会拿我们待过来的id ,到内存里面去找有没有session的 id值

跟这个cookie带过来的一样 ,如果有,就直接返回这个内存空间, 否则就创建新的session空间

想jsp页面传输数据  只能是传输给3个作用域 带给jsp

Session的作用 就是判断 上次你浏览这个网页了吗  如果浏览了  我就有session了

Cookie的作用 就是为了让浏览器默认的给  数据库传值(只要你响应了Session,这个cookie每次都把Session的id带过来)

1为什么用cookie  因为http是无状态的

1cookie 客户端向服务器端传值的操作 你想把密码存储到客户端还是浏览器端

存储到客户端 cookie 设置时间长短 可以把密码和用户名保存到session  (但是是每个客户来的时候都要带过来自己的sessionID) 这时候就要设置为session 带Id的cookie的时间   

1登陆成功后 为什么 把user对象放到session里面   为了正个会话能够共用

2 每次创建session的时候  默认系统就会给创建一个cookie  这个cookie但是还是需要自己响应到浏览器

3 每次访问jsp页面的时候 因为系统默认创建了9个对象  这时候就会有session的id cookie传过来

密码是存到 cookie上面 默认的 每次登陆的时候已经设置了cookie的生命周期  每次登陆的时候都会把cookie带过去

1修改cookie的生命周期 就是在服务器得到cookie  从新给这个cookie设置事件  就把以前的事件覆盖了

把这个密码 账号  写到客户端 就延长cookie的时间  为什么不把用户名密码写到 服务器  因为不知道那个客户什么时候登陆   如果写到服务器也可以  这就要为这个id cookie设置时间 每次从不同的用户  不同的id 获取密码和用户名   进行登陆

目的就是在任何一个页面  都能得到session里面存储的User用户

1 要是session有User用户  说明 还在一个会话中 就不用自动登陆了(要不然每次都自动登陆,服务器也爆炸了)

2要是没在一个会话中就是User为空,就自动登陆,把User用户完成3层查询数据库,存储到session里面,这样就能每个页面都能得到User对象这就是说明 自动登陆了.

3为什么在得到cookie带过来的用户名和密码的时候,重新查询数据库那,因为用户可能传过来的cookie有好多个,可能key名字也一样,这时候就看看你的数据库里面有没有这个用户了.

6 增加重新打开浏览器 session还是使用原来session的方法

1 在一次会话中只有一个session对象(因为对于浏览器请求携带sessionID,要是有就使用原来的,要是没有就创建新的)在运行,在整个会话过程中,一直是这个Id传到服务器的整个项目的每个类和jsp. 在一个session里面可以存储多个键值对 key--value

2 浏览器请求的时候 找到默认的带session Id的那个cookie  key值问 JsessionId   value 是 sessionId   设置这个cookie的时间长度

4 关闭浏览器之后,session销毁了嘛?  

你说没有销毁,为什么我再来的时候取不到以前的值了呢?  因为cookie一次会话 被销毁了 不能带Session的id过来了 所以取不到以前的值了

没有, 因为session是服务器的一块内存空间, 它的销毁不依赖客户端的浏览器关闭还是不关闭。

因为再来的时候,我们的浏览器已经没有了那个session id值,所以就找不到了以前的那一块空间。

* 如果我真的想取 呢?

> 自己取那个sessionid ,然后自己存到cookie里面,并且给cookie设置有效期。

注意: cookie的那个name不能乱写。 JSESSIONID :

5 数据库操作增删改查

对于基本的数据类型 直接数据库内部就能转化    对于日期的转换 重新写类 加进去格式

15 Jsp

1 jsp是什么

<jsp:forward page="/jsp/index.jsp"></jsp:forward> 在jsp里面跳转页面

java server page  : java的服务器端页面, 平常我们使用的html 都是静态网页, 里面的数据内容都是固定的,不跟着时间的推移、 其他情况的改变而改变。但是我们平常都需要动态的去显示一些数据,这些数据来自于数据库,根据不同的查询条件显示出来,那么html就无法做到。 所以这就诞生了JSP.

jsp 可以看成是 能够写java代码的 html网页 。

JSP的背后细节

1. jsp 可以显示html网页内容, 可以写java代码

1. 它其实是一个servlet , jsp的网页内容都是靠里面的out对象写出来的。要是你写的是html代码 直接输出流到浏览器上解析

JSP 注释 区别

语法格式: <%-- 注释内容 --> 编译器看到这句话会直接跳过,不输出>.  在浏览器也看不到源码.在.class文件中也看不到

    <!--输出这句话 , 网页看不到,源码有这句话。 这是html的注释内容 -->  在浏览器上查看源代码 看到源码

    <%--不输出这句话,源码中没有这个 这是jsp的注释内容 --%>

JSP 里面写java代码

    全局变量 <%! int a = 88; %>

    局部变量 <%  int b = 99 ;  %>

    输出变量a的值。 <%=a %>   这里的等号前面不能有空格,每次只能输出一个  想输出多个就多写几个

2 三大指令集 3

语法格式:<%@ 指令名称  %>

1. page

    language : 页面上能写什么语言,默认是java

    contentType : 告诉打开我这个文件那个程序,这是什么类型的文件,请使用什么编码来看

    pageEncoding : 页面编码

    autoFlush: 自动刷新缓冲区

    buffer: 缓冲区大小

    import : 导包

    session : 是否自动创建session true :创建 ,false : 不创建

    errorpage : 当前页面出错后会跳转到指定页面

    isErrorPage : 如果是true , 那么可以使用exception对象,输出错误信息。

    作用:  规定了我们的页面的一些信息, 设置 。。

2. Include 静态包含

效果是 : 能够让某一页面包含 、嵌入另外一个页面的内容 。

    <%@ include file="" %>

    背后细节是把那个被包含的页面的所有源代码全部拿过来一起整合后,输出。out.write.

   作用:提高代码的复用性 ,提取一些共性的头部、 尾部html代码,然后再包含进来。

3. taglib

用于引入标签库 , JSTL 标签库 简化我们的java代码编写

  <%@ taglib prefix="" uri="" %>

3 三个动作标签3

1 jsp:forward

执行跳转,使用请求转发跳转 <jsp:forward page="other02.jsp"></jsp:forward>   两个<><>之间不能有空格

2 jsp:param

跳转的时候,带上参数 <jsp:param name="name" value="aobama" />   forward的标签包裹这个标签

   取参数:<%=request.getParameter("name")%> 这个是再跳转后的页面取值

3 jsp:include 动态包含

    <jsp:include page="other04.jsp"></jsp:include>

    包含另一个页面。 效果与之前的includ指令一样。

4  include指令 和 jsp:include 动作标签的区别

- include指令 静态包含

  1. 只能编译打开的那个页面 成java文件

  2. 把被包含的jsp文件的所有源码全部拿过来,然后一起输出。这里面要是有<%int a=88 >   静态包含另一个页面也有<%int a=99>这时候会报错,因为有两个变量都是a

这种是静态包含 , 把源码拿过去。

- jsp:include 动态包含

  1. 两个页面都会编译。 变成两个java文件

  2. 只会拿被包含的文件编译后的结果过来,然后一起输出。

动态包含 ,只包含运行的结果。

一般来说,如果要包含 jsp网页,一般使用动态包含。 静态包含会事先执行语法校验。 这里面要是有<%int a=88 >   动态包含另一个页面也有<%int a=99>这时候不会报错,因为是分别编译成servlet  在那个页面使用a,就会使用的是那个页面的a  就近原则

4 JSP内置对象9

(9个)  4个作用域 + 2个输出对象 + 3个诸葛亮

1 application   : ServletContext  

1 作用范围  整个项目   2 何时创建:启动服务器 | 发布项目 3 何时销毁 关闭服务器 | 移除项目

2 session  : HttpSession

1作用范围: 一次会话    2何时创建:第一次调用getSession. 3何时销毁,关闭服务器session超时 调用invalidate

3 request  : httpServletRequest

1作用范围 一次请求   2何时创建:来一次请求 3何时销毁 服务器对请求作出响应

4 pageContext : PageContext 其他作用1. 可以获取剩下的8个内置对象。 2. findAttribute  : 从小到大的作用域依次找属性

  1作用范围 当前页面。 2何时创建 :请求jsp就创建 3何时销毁: 关闭页面就销毁

主要是为了让我们在jsp页面里面写更少的java代码。 主要配合 EL 表达使用 extendtion language  扩展的语言 取作用域的值。 ${name}

5 out  :  JspWriter

6 response  : HttpServletResponse

Out和response的区别 : 网页上的文字内容 显示背后使用的就是out.write输出,所以一般的网页内容显示和使用outWrite显示是一样的效果

Out的内容写到response的缓冲区  先输出response的内容 最后再输出out的内容,只要是response输出来的就先输出(包括,ontputStream,write)

7 config  : SerlvetConfig。

8 exception : Throwable  , 捕获异常。

9 page  : Object  其实就是jsp翻译成java文件之后那个类的实例对象。

小知识

1. 访问servlet会不会创建session  不会 1. 访问jsp会不会创建session  会 1. 访问html会不会创建session 不会

5 jsp的取值

1取一般的值<%=a %>

2取list集合的值<%=color%> 就直接取出来了list里面的所有值   <%=colorslist.get(0)%> 得到索引为0的值

3取数组的值<%=arr%> 直接得出数组的值

4取Map集合的值<%=map.get(key)%>  

4取对象<%=user%>得到的是对象的        取对象的属性<%=user.name %>

16 Jsp模式&el&jstl

一、EL表达式

- EL表达式的作用

简化我们在jsp里面写java代码。  语法格式 ${表达式}

1 EL表达式的作用

  1. 取作用域的值 (用的最多)

El表达式的内置对象 11

EL表达式的内置对象(共11个)  4+2+2+3

    * 四个作用域 (和取值相关。只负责取值,存值必须在jsp<%%>自己存值)

    pageScope

    requestScope

    sessionScope

    applicationScope

    * 2个是参数相关

    param

    paramValues

    * 2个是头相关

    header

    headerValues

    * 3个其他

    cookie  : 获取cookie的值

    initParam  : 全局配置参数

    pageContext : pageContext对象

EL表达式取值

1. 如果在作用域当中没有这个值,那么在页面上什么都不会显示,也不会显示null

1. 取值用法 :

       ${pageScope.pname } , 强制指定了到这个作用域取找,如果找不到,也什么都不显示

       ${pname} : 一个一个的作用域开始找,从小的开始找到大。 如果没有找到就什么都不显示

1获取数组&map集合的值

- 数组获取

数组有下标,所以直接使用[] 配合下标来取即可

     <%

     String [] array = {"aa","bb","cc","dd"};

     request.setAttribute("arrays", array);

     %>

     <h2>使用EL表达式取数组的值</h2><br>

     ${arrays[0] } , ${arrays[1]} , ${arrays[2]} , ${arrays[3]}  , ${arrays[30] } (下标没有30 取不到不显示)

- map取值

由于map是没有下标的,所以需要使用 . 来获取。

    <%

     Map<String , Object> map = new HashMap<String ,Object>();

     map.put("name", "aobama");

     map.put("age", 99);

     map.put("gender","男");

     map.put("address.aa","USA");

     request.setAttribute("map", map);

    %>

    EL表达式取值有一个规律,如果要取的值有下标用 【下标】 , 如果没有,就用 .

    <h2>使用EL表达式取map的值</h2><br>

    ${map.name } , ${map.age }, ${map.gender }, ${map["address.aa"] }

EL表达式 :  取值 ... 取各种各样的值。 取作用域的值。

1 取普通作用域的值

使用步骤  首先存值  才能用el取值

1 按普通手段取值<br>

<%= pageContext.getAttribute("name")%>

<%= request.getAttribute("name")%>

<%= session.getAttribute("name")%>

<%= application.getAttribute("name")%>

2 使用EL表达式取出作用域中的值

${ pageScope.name }

${ requestScope.name }

${ sessionScope.name }

${ applicationScope.name }

2 取数组/list集合的值

由于List本身也是有下标的,所以我们也可以使用这种方式来获取它的值。

<%

String [] a = {"aa","bb","cc","dd"};

pageContext.setAttribute("array", a);

%>

使用EL表达式取出作用域中数组的值

${array[0] } , ${array[1] },${array[2] },${array[3] }

获取list集合的值  

<%List<String> colorslist = new ArrayList<String>();

colorslist.add("red");

colorslist.add("yellow");

colorslist.add("blue");

colorslist.add("green");

colorslist.add("black");

pageContext.setAttribute("color", colorslist);

%>

在EL表达式中  对于所有的取值 都必须有上面的存值 但是对于用jsp本身取值 不用存储直接就可以取值

${color }得到list集合里面所有的值    ${color.get(2) } 根据索引得到元素的值   

3 取map集合的值

<%

Map map = new HashMap();

map.put("name", "zhangsna");

map.put("age",18);

map.put("address","北京..");

map.put("address.aa","深圳..");

pageContext.setAttribute("map", map);

%>

使用EL表达式取出作用域中Map的值<br>

${map.name } , ${map.age } , ${map.address }  , ${map["address.aa"] }(对于取值里面有.点的 要用[]括起来分别)

4 取对象的字段值

<%

User user = new User("zhangsan",18);

session.setAttribute("u", user);

%>

${ u.name }  , ${ u.age }

5 取值总结

1 如果这份值是有下标的,那么直接使用[]

<%

String [] array = {"aa","bb","cc"}

session.setAttribute("array",array);

%>

${ array[1] } --> 这里array说的是attribute的name

2 如果没有下标, 直接使用 .的方式去取

<%

User user = new User("zhangsan",18);

session.setAttribute("u", user);

%>

${ u.name }  , ${ u.age }

> 一般使用EL表达式,用的比较多的,都是从一个对象中取出它的属性值,比如取出某一个学生的姓名。

6 EL表达式还可以执行运算/逻辑判断。

1 逻辑判断

2 3元运算符${1>2?"1>2":"1<2" }

2 JSTL

java standard tag library   java的标准标签库   这可以看做是jsp一个小框架

- 它的作用  : 也是为了简化我们的java代码。  判断逻辑 | 遍历操作。

- JSTL版本 1. 0 : 不支持EL表达式 1.1 : 支持EL表达式(所以现在基本上用的是1.1版本)

使用步骤

1. 导入jar包  jstl.jar  standard.jar

2. 在顶部使用taglib 指令集 导入标签库

     <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

1 - c:set 用于存值

这是默认是往pageScope 里面存值  , 当然要可以通过scope属性来更改存储的作用域4个作用域。

    语法格式 :<c:set var="" value="" scope=""></c:set>

把一个值 : aobama的存储到作用域当中, 对应的那个name : name<br>

 <c:set var="name"  value="aobama4" scope="request"></c:set>

2 - c:if条件表达式

用于判断,如果条件满足则显示标签中间的内容。需要 主要 配合EL表达式来使用 。

    语法格式:

     <c:if test="">

  中间的内容将会显示

  </c:if>

    例子:

     <c:if test="${1 ==1}"> 这里面test只能是el表达式 

     aaaaaa

     </c:if>

1 判断集合是否为空  <c:if test="${empty list}">没有商品</c:if>

<c:if test="${not empty list}"> 不为空怎么样 </c:if>

2 判断是否相等eq  ne

 <%      int n1 = 20; request.setAttribute("n1", n1);     %>

        <c:if test="${ n1 eq 10 }" var="i">

           n1=10

        </c:if>

        <c:if test="${ n1 ne 10 }">

            n1!=10

        </c:if>

        ${ i }

结果是  n1! = 10 false

3 - c:foreach 循环

     1 遍历数字

       直接遍历数字,从 几遍历到几  把遍历到的数字输出。  

       从1开始遍历 到10 ,遍历出来的每一个数字都存储到作用域里面去, 作用域对象的名字叫做 i , 下面直接取i的值即可。

       <c:forEach begin="1" end="10" var="i">

       ${i }<br>

       </c:forEach>

    2 遍历对象集合

     <%

     List<User> list = new ArrayList<User>();

     list.add(new User("aa",15));

     list.add(new User("bb",25));

     list.add(new User("cc",35));

     list.add(new User("dd",45));

     list.add(new User("ee",55));

     pageContext.setAttribute("list", list);

     %>

     <br>遍历作用域中的对象 list  ,遍历一次存一次, 存到作用域中,作用域的对象名叫做 user .后面的varstatus 是指遍历的一些状态。 如果要获取遍历的次数,可以使用它 <br>   这是得到的每个对象

     <c:forEach  items="${list }" var="user" varStatus="status">

     ${status.count} ---- ${user.name } ---- ${user.age }<br>

     </c:forEach>

3遍历list集合

<%

  List userList = new ArrayList();

  userList.add("Tom");

  userList.add("Make");

  userList.add("Lina");

 %>

<c:forEach var="name" items="<%=userList%>" varStatus="status">

     ${status.count}

         ${name}

  </c:forEach>  

结果是 1 Tom 2 Make 3 Lina

4遍历map集合

<c:forEach items="${map }" var="cartMap">

${cartMap.key}----${cartMap.value }

</c:forEach>

3 JSP开发模式

开发模式的演变

MVC设计模式

- model 模型层 , 主要用来处理数据封装 ,业务逻辑处理

- view 视图层 , 用于显示界面

- control 控制层  : 接收和处理请求

17 事务

什么是事务 : 逻辑上的一组操作,要么全部成功,要么全部失败(这组操作不可分割)

1 MySQL管理事务的方式

1- 自动管理(默认):一条SQL就是一个单独的事务,事务是自动提交的

  - 关闭自动提交(仅对当前窗口有效)

    - show variables like 'autocommit'; 查看当前事务是否自动提交

    - set autocommit = off; 关闭自动提交

2- 手动事务:

  - 手动开启事务

    - start transaction : 开启事务 (对数据的操作在临时表中进行)

    - rollback : 回滚事务 (取消操作)

    - commit : 提交事务 (确认操作)

    - 在事务管理中执行sql,使用数据库内临时表保存,在没有进行事务提交或者回滚之前,其它用户无法看到事务操作的结果

    - SQL语言中只有DML才能被事务管理(insert/update/delete)</font>

2 JDBC管理事务

l   - <font color='red'>Connection.setAutoCommit(false);// 开启事务

l   - connection.commit();// 提交事务

l   - connection.rollback();// 回滚事务

1 使用步骤 3种使用方法

1直接自己创建Connection  然后让这个Connection 传输过去(因为JDBC的事物是Connection 操作的,必须同一个对象)

2使用QueryRunner queryRunner = new QueryRunner(); 不从C3P0的链接池里面取

queryRunner.update(connection, sql, amount, sender);  用自己传值过来的connection

queryRunner.update(connection, sql, amount, receiver);

2 设置回到那个回滚点  

 事务回滚点 SavePoint (类似与游戏中的存档)

  - 当事务特别复杂,有些情况不会回滚到事务的最开始状态,需要将事务回滚到指定位置

- 核心API

Savepoint savepoint = null;

savepoint = connection.setSavepoint();

代码实例

public void test2() throws SQLException {

// 向数据库中插入数据,5000.

// 如果发生了异常,数据库中保存的数据的条数只能是1000的整倍数

Connection connection = null;

PreparedStatement statement = null;

Savepoint savepoint = null;

try {

connection = JDBCUtils.getConnection();

// 开启事务

connection.setAutoCommit(false);

// 设置回滚点

savepoint = connection.setSavepoint();

String sql = "insert into person values (?,?)";

statement = connection.prepareStatement(sql);

for (int i = 1; i <= 5000; i++) {

statement.setInt(1, i);

statement.setString(2, "name" + i);

// 添加到批处理

// 批处理只适用于批量的添加或修改数据.sql语句一样,但是具体参数不一样

statement.addBatch();

if (i == 2222) {

int k = 1 / 0;

}

// 每200条执行一次批处理

if (i % 200 == 0) {

statement.executeBatch();

statement.clearBatch();

}

// 每1000条,重新设置一次回滚点

if (i % 1000 == 0) {

savepoint = connection.setSavepoint();

}

}

statement.executeBatch();

statement.clearBatch();

// 提交事务

connection.commit();

} catch (Exception e) {

// 回滚到2000条数据的存档点

connection.rollback(savepoint);

// 因为这一次回滚,不是回滚到最开始的起点,所以要提交事务

connection.commit();

} finally {

JDBCUtils.release(statement, connection);

}

  

3 DBUtils管理事务

这是- Apache DBUtils (轻量级)

为什么使用:  - 使用方便 - 只是对JDBC程序进行简单封装,从而简化开发者 创建连接、结果集封装、释放资源

- 核心API  - QueryRunner : 是DBUtils 核心操作类 - ResultSetHandler : 结果集封装处理器

- QueryRunner

  - 如果使用 QueryRunner(DataSource ds) 构造QueryRunner 对象,数据库事务交给DBUtils框架进行管理.默认情况下每条sql就是一个事务,结合以下API使用

    - query(String sql, ResultSetHandler<T> rsh, Object... params)

    - update(String sql, Object... params)

  - 如果使用 QueryRunner() 构造QueryRunner , 需要自己管理事务,因为框架没有连接池无法获得数据库连接.,结合以下API使用

    - query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params)

    - update(Connection conn, String sql, Object... params) </font>

- DbUtils

  - commitAndClose(Connection conn) : 提交并释放资源.异常需要自己处理

  - commitAndCloseQuietly(Connection conn) : 提交并释放资源.异常由框架处理(其实没处理)

  - rollbackAndClose(Connection conn) : 回滚并释放资源.异常需要自己处理

  案例实现之考虑事务

- 如果不考虑事务,会导致转账钱丢失的问题.所以必须考虑事务

- 如果要避免上述问题,只需要保证所有的操作使用同一个连接对象即可

- 解决方法

  - 传递参数Connection

  - 线程绑定ThreadLocal

- ThreadLocal简介  就是一个map集合  把Connection 封装到里面

  - 作用 : 把一个操作对象和当前线程绑定在一起. 其内部维护了一个Map集合.key就是当前线程,value就是要绑定的内容

  - 常用API

    - set(T value) : 把一个对象和当前线程进行绑定.等价于Map.put(Thread.currentThread(),value)

    - T get()  : 获取和当前线程绑定在一起的对象.等价于Map.get(Thread.currentThread())

    - remove() : 移除和当前线程绑定在一起的对象.等价于Map.remove(Thread.currentThread())

4事务特性

事务的四大特性:

  1- 原子性(Atomicity):事务的一组操作不可分割,要么都成功,要么都失败

  2- 一致性(Consistency):事务前后数据保持完整性.转账前A和B账户总和2000元,转账后总和还是2000 元

  3- 隔离性(Isolation):并发访问时,事务之间是隔离的,一个事务不应该影响其它事务的运行效果

  4- 持久性(Durability):当事务一旦提交,事务数据永久存在,无法改变 </font>

- 企业开发中一定要保证事务原子性

- 事务最复杂问题都是由事务隔离性引起的

隔离性

- 不考虑事务隔离将引发的问题

  - 脏读:一个事务读取另一个事务未提交的数据.这是数据库隔离中最重要的问题

  - 不可重复读:一个事务读取另一个事务已提交的数据,在一个事务中两次查询结果不同(针对update操作)

  - 虚读:一个事务读取另一个事务插入的数据,造成在一个事务中两次查询记录条数不同(针对insert操作)

- 数据库为了解决三类隔离引发问题,提供了四个数据库隔离级别(所有数据库通用)

  -Serializable : 串行处理.可以解决三类问题

  - Repeatable read :可以解决不可重复读、脏读,但是会发生虚读.是MySQL的默认级别

  - read committed : 可以解决脏读,会发生不可重复读、虚读.是Oracle的默认级别

  - read uncommitted : 会导致三类问题发生 </font>

  - 按照隔离级别从高到低排序 : Serializable  > Repeatable read > read committed > read uncommitted

  - 数据库隔离问题危害的排序 : 脏读> 不可重复读 > 虚读

  - 多数数据库厂商都会采用Repeatable read或read committed两个级别.

- 更改事务隔离级别的语句

  - set transaction isolation level 设置事务隔离级别

    - select @@tx_isolation;查询当前事务隔离级别

1 隔离级别引发问题的小实验

- 脏读问题(read uncommitted)

  - 开启两个窗口,执行一次查询,获得一个结果

  - 将B窗口隔离级别设置为read uncommitted

    - set session transaction isolation level read uncommitted;

  - 在A、B窗口分别开启一个事务 start transaction;

  - 在A窗口完成转账操作

    - update account set money= money - 200 where name='aaa';

    - update account set money= money +200 where name='bbb';

  - 在B窗口进行查询,会读取到A窗口未提交的转账结果

  - A窗口进行回滚rollback, B窗口查询结果恢复之前

- 不可重复读(read committed)

  - 开启两个窗口,执行一次查询,获得一个结果

  - 将B窗口隔离级别设置为read committed

    - set session transaction isolation level read committed;

  - 在A、B窗口分别开启一个事务 start transaction;

  - 在A窗口完成转账操作

    - update account set money= money - 200 where name='aaa';

    - update account set money= money +200 where name='bbb';

  - 此时在B窗口执行查询操作,数据不会发生改变.避免了脏读问题

  - A窗口执行commit,B窗口再次执行查询,会读取到A窗口提交的结果.注意此时B窗口没有提交事务,也就是在同一事务中,读取到了两个结果.发生不可重复读问题

- 虚读(Repeatable read)

  - 开启两个窗口,执行一次查询,获得一个结果

  - 将B窗口隔离级别设置为Repeatable read

    - set session transaction isolation level repeatable read;

  - 在A、B窗口分别开启一个事务 start transaction;

  - 在A窗口完成转账操作

    - update account set money= money - 200 where name='aaa';

    - update account set money= money +200 where name='bbb';

  - 此时在B窗口执行查询操作,数据不会发生改变.避免了脏读问题

  - A窗口执行commit,B窗口再次执行查询,数据仍然不会发生改变.避免了不可重复读.

  - 此时如果在A窗口插入一条数据,而B窗口可以查询到,就是发生了虚读问题.但是这种情况发生的几率非常小.

- Serializable

  - 开启两个窗口,执行一次查询,获得一个结果

  - 将B窗口隔离级别设置为read serializable

    - set session transaction isolation level serializable;

  - 在A、B窗口分别开启一个事务 start transaction;

  - 在B窗口执行查询操作

  - 在A窗口执行插入操作.此时A窗口将会被卡住,不会执行语句.直到B窗口提交或回滚,释放数据库资源

- 在JDBC中,可以通过Connection.setTransactionIsolation(int level) 来设置隔离级别.如果没有设置.会采用数据库的默认级别

扩展

2失更新问题和悲观锁乐观锁机制

- 事务丢失更新问题 : 两个事务同时读取同一条记录,A先修改记录,B也修改记录(B不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。

- 解决丢失更新的两种方式

  - 事务和锁是不可分开的,锁一定是在事务中使用 ,当事务关闭锁自动释放

  - 悲观锁

    - 假设丢失更新会发生

      - 使用数据库内部锁机制,进行表的锁定,在A修改数据时,A就将数据锁定,B此时无法进行修改

    - 在mysql中默认情况下,当你修改数据,自动为数据加锁(在事务中),防止两个事务同时修改数据

    - 在mysql内部有两种常用锁

      - 读锁(共享锁)

        - 一张表可以添加多个读锁,如果表被添加了读锁(不是当前事务添加的),该表不可以修改

        - 语法 : select * from account lock in share mode;

        - 共享锁非常容易发生死锁

      - 写锁(排它锁)

        - 一张表只能加一个排它锁,排他锁和其它共享锁、排它锁都具有互斥效果 。

        - 如果一张表想添加排它锁,前提是之前表一定没有加过共享锁和排他锁

          - 语法 :select * from account for update ;

  - 乐观锁

    - 假设丢失更新不会发生

    - 使用的不是数据库锁机制,而是一个特殊标记字段 : 数据库timestamp 时间戳字段

- rollbackAndCloseQuietly(Connection conn) : 回滚并释放资源.异常由框架处理(其实没处理)

5 thows 和try-catch

1因为mysql语句写错 抛出的错误

int inMoney = dao.inMoney(connection,username02,money);  // 这个抛出的

2因为在数据库找不到名称,转账失败 抛出错误

if (inMoney != 1) {

throw new RuntimeException("转入钱的时候---没有这个人,转账失败");  //这个抛出 直接能打印出

}

3因为整个事物中,有中间代码写错,抛出的错误

6 批量处理sql执行语句

statement = connection.prepareStatement(sql);

for (int i = 1; i <= 5000; i++) {

statement.setInt(1, i);

statement.setString(2, "name" + i);

// 添加到批处理

// 批处理只适用于批量的添加或修改数据.sql语句一样,但是具体参数不一样

statement.addBatch();     //添加到批量处理

if (i == 2222) {

int k = 1 / 0;

}

// 每200条执行一次批处理

if (i % 200 == 0) {

statement.executeBatch();   //每

statement.clearBatch();

}

18 手机商城增删改查

先看是全局访问还是 部分访问  然后请求 传值      响应传值      接收传值 解析传值

1现在所学的,都是前端页面  1如何请求数据库 局部ajax  还是全部    2请求怎么带参数文本框(get,post) 请求链接上拼接参数  json传值

2数据库的处理servlet  接收数据,----3层的处理结构

3响应 把数据库的值响应到jsp  json传值   四个作用域传值(到时候用el接收值,或者el框架jstl接收 与 遍历)

4到jsp页面 接收参数   然后通过js修改html的标签  属性  文本 ------或者用jquery框架修改

1设置编码必须放到第一行  放到下面可能不起到作用

写代码, 1需要的功能 ----2这个功能要多少数据------3分层执行得到数据----4返回结果集 ------5解析数据  16写代码的思路  需要几个参数   1需要的是什么功能  ---2要几个参数  3怎么返回参数

1  传参数,相当于一个标记,  四个作用域的传值 取值el表达式

2  绑定事件的跳转

正确  location.href = "${pageContext.request.contextPath }/product?action=delByPid&pid=" + pid   

错误  location.href = "${pageContext.request.contextPath }/product?action=delByPid&pid=${list.pid}" 在jsp页面javascript代码中后面的el表达式不识别

3  只要在jsp页面中取值pname   然后判断   后面的修改编码就不起作用   必须先在最上面修改编码

request.setCharacterEncoding("utf-8");

response.setContentType("text/html;charset=UTF-8");

4  new Date()  是怎么改变成日期

5  UUID 的使用

6  3秒钟跳转页面<meta http-equiv="refresh" content="3;url=index.jsp">

7  beanUtils的使用 数据怎么封装的

// 参数1 : 被封装的对象

// 参数2 : form表单中name和value组成的map集合

BeanUtils.populate(product, request.getParameterMap());

8  在点击事件  传值的时候必须带上单引号  传输自己的时候 (this)不带引号

9监听 submit 代码 不让其自动提交 有自己来控制是否提交

<form action="${pageContext.request.contextPath }/product" οnsubmit="return confirm('确认要批量删除吗?')" method="post">

用来确认 submit是否可以点 document.getElementById(“sub”).disabled=true   就是按钮不能点了   false能点击

用来确认下面提交过来的 submit 不是直接提交数据   而是有我自己来控制

10 删除数据的时候 确定是否删除    传值的时候必须带上单引号 才是传入的一个int数  要不然是字符串 不识别

<a οnclick="confirmDel('${item.pid }')" href="javascript:void(0)">删除</a>  用点击事件来控制 超链接

用js代码来控制是否全部删除  然后再跳转

<script type="text/javascript">

function confirmDel(pid) {

var confirmResult = confirm("确认删除吗");

if (confirmResult) {

location.href = "${pageContext.request.contextPath }/product?action=delByPid&pid="

+ pid

}

}

</script>

11 封装数据 一个对象里面的参数可以包含另一个对象和多个对象封装, 可以变成参数pageBean 可以用数据库查询多次 然后的得到数据  存储到工具类里面,然后再返回数据

12 向上取整int totalPageNums = (int) Math.ceil(totalRows * 1.0f / PageBean.PAGE_SIZE);

13 <center>标签的意思

14两种获取链接的方式   

15所有的判断都是在<c:if > 里面完成的

</c:if>

<c:if test="${pageBean.currentPageNum != pageBean.totalPageNums }">

<a href="${pageContext.request.contextPath }/product?action=getPageData&pnum=${pageBean.currentPageNum+1 }">下一页</a>

</c:if>

17从jstl里面得到的数据  只能从jstl符号里面才能显示出来

18 Java增强方法的三种途径

1 - 类继承 、方法覆盖  - 必须控制对象创建,才能使用该方式

2 - 装饰者模式 - 必须和目标对象实现相同接口或继承相同父类,特殊构造器(传入被包装对象)

3 - 动态代理  - 根据原对象在内存中构造代理对象,原对象的所有方法,都将执行代理对象的invoke方法

19 Ajax

是js的一个功能,部分请求与响应的过程

- Asynchronous Javascript And XML, 异步JavaScript和XML. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新

- 同步 : 在普通的BS模式下,访问流程是客户端提交请求 -> 等待服务器处理 -> 服务器处理完毕返回,在等待期间客户端不能干任何事

- 异步 : 在AJAX模式下,通过事件触发请求 -> 服务器处理(此时客户端可以继续做其他的事情) -> 处理完毕.

- 运行原理 : 页面发起请求,会将请求发送给浏览器内核中的Ajax引擎,Ajax引擎会提交请求到客户端,在这段时间里,客户端可以任意进 行 任意操作,直到服务器端将数据返回给 Ajax引擎后,会触发你设置的事件,从而执行自定义的js逻辑代码完成某种页面功能

1 ajax入门程序:

步骤:

1.创建一个核心对象 XMLHttpRequest

2.编写一个回调函数

3.编写请求方式和请求的路径(open操作)

4.发送请求(send操作)

1对于传输的类型为 “text”  可以传boolean类型  在jsp页面能收到boolean类型

2 对于传输的类型为”text” 格式 可以传输对象 对象判断为空的时候要 带上引号””

function(data) {

if (data == "null") {

$("#usename_msg").html("可以使用用户名");

} else {

$("#usename_msg").html("不可以使用用户名");

$("#sub").prop("disabled", true);

}

}, "text");

});

1 ajax-api详解:

- AJAX 使用步骤5

- JavaScript的AJAX其实就是围绕浏览器内内置的Ajax引擎对象进行学习的

- 使用JavaScript的AJAX有以下几个固定步骤

 1 - 创建Ajax引擎对象 0:核心对象创建

 2 - 为引擎对象绑定监听 1:调用了open方法

 3 - 设置访问地址  

 4 - 发送请求  2:调用了send方法

 5 - 接收响应  4:响应已经完成(使用的是这个状态)  3:部分响应已经生成(没有意思)

常用属性:

onreadystatechange:检测readyState状态改变的时候

readyState:ajax核心对象的状态

status:状态码

常用方法:

open("请求方式","请求路径"[,"是否异步"]):设置请求的方式和请求的路径

send(["参数"]):发送请求 参数是请求方式为post的时候的参数

setRequestHeader("content-type","form表单enctype属性"):设置post请求的参数的类型 必须放在send方法之前.

- 示例代码

function fn1() {

// 1.创建引擎对象

var enginee = new XMLHttpRequest();

// 2. 绑定一个监听, 监听引擎的变化

enginee.onreadystatechange = function() {

// readyState:代表引擎的状态,4为请求成功,返回数据

// status:代表请求状态,200为请求成功

if (enginee.readyState == 4 && enginee.status == 200) {

// 5.接收响应

alert(enginee.responseText);

}

};

// 3.设置访问地址

// 第一个参数:指定请求方式

// 第二个参数:指定请求地址

// 第三个参数:是否使用异步.true异步,false同步

enginee.open("GET", "/AJAX/AJAX_Servlet", true);

// 4.发送请求

enginee.send();

}

2 jquery中的ajax:

 1 了解:jquery对象.load(url,params,function(数据){});

2 ★: $.get(url,params,function(data数据){},type);

url:请求的路径  必写

params:请求的参数 参数为key\value的形式 key=value  {"":"","":""}

fn:回调函数 参数就是服务器发送回来的数据

type:返回内容格式,xml, html, script, json, text, _default。    以后用"json"

 Data: 数据库里面返回的数据

3 ★: $.post(url,params,function(数据){},type);

若结果为json格式,  打印返回值的时候是一个对象

例如若json为 {"result":"success","msg":"成功"}

获取msg 只需要 参数.msg

4 理解:

$.ajax([选项]);

选项的可选值:

url:请求路径

type:请求方法

data:发送到服务器的数据

success:fn 成功以后的回调

error:fn 异常之后的回调

dataType:返回内容格式 经常使用json 转换更

async:设置是否是异步请求

例如:

function fnGet() {

$.get("/AJAX/AJAX_Servlet",// 指定请求地址,必选

"name=张三&psw=123",// 指定请求参数,键值对或json格式.可选

function(data) {//指定处理响应数据的函数,可选. 请求成功以后jQuery框架会调用该函数

// data就是服务器返回的数据

alert(data);

}, //

"text"//服务器返回的数据类型,可选

)

}

function fnPost() {

$.post("/AJAX/AJAX_Servlet",// 指定请求地址,必选

"name=张三&psw=123",// 指定请求参数,键值对或json格式.可选

function(data) {//指定处理响应数据的函数,可选. 请求成功以后jQuery框架会调用该函数

// data就是服务器返回的数据

alert(data);

}, //

"text"//服务器返回的数据类型,可选

)

}

function fnAJAX() {

$.ajax({

url : "/AJAX/AJAX_Servlet",// 指定请求地址

type : "POST",// 指定请求方式,"POST" 或 "GET"

async : true,//指定是否异步

data : "name=张三&psw=123",// 指定请求参数,键值对或json格式.

dataType : "text",//服务器返回的数据类型

success : function(data) {// 指定请求成功后的回调函数

alert(data);

}

})

}

*  回调函数

 *   如果服务器发送的数据 response.setContentType("application/json;charset=UTF-8");  //直接响应json对象

 *    data获得json对象

 *   如果服务器发送的数据 response.setContentType("text/html;charset=UTF-8");  //响应文本

 *    data获得 字符串 数据,将采用“参数4”设置 参数类型

 *  不建议发送中文,存在乱码

3 JSON的解析

Json 对象    {"key1":obj,"key2":obj,"key3":obj...}     直接是对象导航的形式使用

Json 文本   ”{"key1":obj,"key2":obj,"key3":obj...} ”   对于这个文本要转化成json对象才能正常使用

- 全称 JavaScript Object Notation, 是一种轻量级的数据交换格式.易于人阅读和编写,同时也易于机器解析和生成

- 数据格式和解析:  对2中json形式的解析 看到对象就.   看到集合 和数组就[]    - 对象格式和数组格式相互嵌套

1 解析字符串形式  首先从后台传过来的就是字符串形式 response.getwrite().write(hehe)  

解析的时候直接 data得到的就是”hehe” 

2 解析对象格式和Map格式 - 对象格式:{"key1":obj,"key2":obj,"key3":obj...}

Data 得到的是对象   然后data.name  就是得到对象里面字段的值

3 解析数组和list形式  数组格式:[obj,obj,obj...]

先遍历, 普通for  然后是  data[index]  

-Map格式 {"username":"jack","password":"1234"}

alert(user.username+ arr[1]+data[1].title); 对象和数据不同的取值方式

答案说明:JSON对象格式

 {"key":"value","key":"value",....}

 键和值使用冒号分隔。

 标准规范要求key必须使用双引号,value如果没有使用双引号表示变量。

  - JSON是JavaScript的原生内容, 所以可以直接获取JSON中的内容

在json中存储list集合和数组用[]存储的  因为有索引

在json中存储map集合和对象用{}存储的  没有索引用  存储Map集合实例

Map<String, String> map = new HashMap<String, String>();

map.put("username", "jack");

map.put("password", "1234");

String str = JSONObject.fromObject(map).toString();

System.out.println(str);

{"username":"jack","password":"1234"}

4 JSON的生成gson的使用

在json中所有的都是打印的字符串   null也是字符串    可以传空值

- 1 导入gson.jar

- 2 使用以下API,将对象转化为json字符串

// 3 创建Gson对象 Gson gson = new Gson();

//4 把数据转换为json格式 String json = gson.toJson(list);  可以接收 对象类型/集合/数组 能把字段转换成json类型

在json中   集合和数组 都是[] 对象是{}

步骤分析:

将js原生ajax修改成jquery的ajax

案例3-模仿百度搜索

需求:在一个文本框中输入一段内容,keyup的时候发送一个ajax请求,去数据库中查找相应的内容,在页面上展示

步骤分析:

1.表

create table keyword(

id int primary key auto_increment,

kw varchar(20)

);

2.页面

3.在文本框输入内容 keyup的时候 发送ajax请求 将输入值传递到后台

4.将返回的数据展示

案例4-省市联动

需求:

先有一个省份的下拉选,根据选择省份,从而动态的市下拉选中加载所有的市.

步骤分析:

1.表

2.页面上有两个下拉选 省份的下拉选一般是固定的 页面加载的时候读取所有的省份

3.当省份改变的时候,获取省份的信息,发送一个ajax请求,去市的表中查询相应省份的所有市,然后将他们加载到市下拉选上

4.selectProServlet selectCityServlet

技术分析:

json

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。

json格式:

格式1:value可以为任意值

{"key":value,"key1":value1}

格式2:e可以为任意值

[e1,e2]

jsonlib工具类,可以使对象转换成json数据

1.导入jar包

2.使用api

JSONArray.fromObject(对象)  数组和list转换成json

JSONObject.fromObject(对象)  bean和map 转换成json

4 json:轻量级的数据格式:

格式1:{"key":value,"key1":value}

格式2:[e1,e2]

jsonlib: 1.导入jar包

2.使用api

JSONArray.formObject(数组或者list);

JSONObject.formObject(bean或者map);

获取jquery对象:

$("选择器") jQuery("选择器");

jquery对象>>dom对象

方式1:  jquery对象.get(index);

方式2:  jquery对象[index]

dom对象>>jquery对象

$(dom对象)

页面载入 $(function(){})

派发事件 jquery对象.事件(function(){...});

选择器:

#id值  .class值  标签名  [属性]  [属性='值']

a b:后代    a>b:孩子  a+b:大弟弟  a~b:所有弟弟

:first :last :odd :even :eq|gt|lt(index)

:hidden

:checked  :selected

属性和css: prop|attr css

文本 标签体 val() html() text()

文档处理

内部插入append prepend

外部插入after before

删除remove

效果: 隐藏|显示show()  hide()

淡入淡出fadeIn()  fadeOut()

滑入滑出slideDown()  slideUp()

遍历 jquery对象.each(function(){ });

20 listener/filter

listener

1域对象变更监听

- 一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行

- 由于Servlet技术存在三个数据域范围:ServletContext 、HttpSession、ServletRequest,所以Servlet监听器主要监听上面三个域对象的创建和销毁、属性变更以及状态变化

- Servlet监听器分类:

  - 三个域范围对象创建和销毁监听器

  - 三个域范围对象属性变更监听器

  - HttpSession范围中对象的自我状态感知监听器

监听内容:

监听三个对象的创建和销毁

监听三个对象属性的变化

监听session中javabean的状态

注意:listener全部是接口

1 ServletContextListener(掌握)

作用 1- 可以使用注解,可以在web.xml中配置

2- 监听 ServletContext 对象的创建和销毁

3- ServletContext对象生命周期

 生命周期 - 服务器启动时创建,服务器正常关闭时销毁

- ServletContextListener 企业应用

  - 保存全局唯一数据对象,获得ServletContext

  - 加载框架配置文件 spring  

  - 启动定时器(固定时间需要自动运行程序)

2 HttpSessionListener

1- 可以使用注解,可以在web.xml中配置

2- 监听session对象创建和销毁

3- Session的生命周期

1.   - Session的创建 :request.getSession();

2.   - Session的销毁 :服务器非正常关闭、session超时(配置web.xml setMaxInactiveInterval)、session.invalidate

3.   - tomcat服务器正常关闭时,会将session中的数据序列化硬盘上

3 ervletRequestListener

1- 可以使用注解,可以在web.xml中配置

2- 监听request对象创建销毁

3- request的生命周期

l   - request创建 :客户端提交请求时

l   - request销毁 ;响应结束时

2域对象属性变更监听器 3

1 ServletContext域对象监听

- 可以使用注解,可以在web.xml中配置

- Servlet规范定义了监听 ServletContext, HttpSession, HttpServletRequest 这三个对象中的属性变更信息事件的监听器

  - ServletContextAttributeListener

  - HttpSessionAttributeListener

  - ServletRequestAttributeListener

- 这三个接口中都定义了三个方法来处理被监听对象中的属性的增加,删除和替换的事件,同一个事件在这三个接口中对应的方法名称完全相同,只是接受的参数类型不同

  - attributeAdded() : 某个属性被添加时,web容器调用事件监听器的这个方法进行相应

  - attributeRemoved() : 某个属性被移除时,web容器调用事件监听器的这个方法进行相应

  - attributeReplaced() : 某个属性被替换时,web容器调用事件监听器的这个方法进行相应

Request里面 replaced   remove  都是 打印的上个属性的值

3 HttpSession中对象状态感知监听器

- 无需配置注解,或在web.xml中配置

- HttpSession中对象的状态

  - 将对象保存在Session中

  - 将对象从session中移除

  - 当一个对象长时间存在Session中,而Session没有使用,将Session对象数据序列化硬盘(钝化)

  - 当使用一个已经钝化对象,需要从硬盘上将对象加载到内存(活化)

1 - HttpSessionBindingListener

  - 负责绑定和解除绑定的监听

  - 如果一个对象已经在session存在中,再次存入时,会触发一次绑定和一次解除绑定

2 - HttpSessionActivationListener

  - 负责钝化和活化的监听

  - 示例代码

    - 在当前工程 WebRoot/META-INF/context.xml文件中配置以下内容

6 钝化的时候要实现io接口里面的 序列化   要不然钝化不成功

<Context>

<!-- maxIdleSwap="1" 代表如果一个session超过1分钟没有使用,就钝化到硬盘 -->

<Manager className="org.apache.catalina.session.PersistentManager"

maxIdleSwap="1">

<!-- directory="it315" 代表钝化文件保存的目录为it315.这个目录会生成在tomcat/work目录 -->

<Store className="org.apache.catalina.session.FileStore"

directory="it315" />

</Manager>

</Context>

实现对应的JavaBean.需要特别注意对应的JavaBean需要实现Serializable接口,否则是无法序列化到本地的.

4 定时器

- Timer

  - schedule(TimerTask task, Date when) : 在指定的具体时间去执行执行某一任务,只执行一次

  - schedule(TimerTask task, long delay) : 在指定的延时时间之后去执行某一任务,只执行一次

  - <font color='red'>schedule(TimerTask task, Date when, long period) : 在指定的具体时间开始执行某一任务,不管任务是否执行完毕,一旦时间过了period参数指定的时间间隔,再次开启任务去执行.

  - schedule(TimerTask task, long delay, long period) : 在指定的延时时间开始执行某一任务,不管任务是否执行完毕,一旦时间过了period参数指定的时间间隔,再次开启任务去执行.

  - scheduleAtFixedRate(TimerTask task, long delay, long period) : 在指定的延时时间开始执行某一任务,执行完毕后,一旦时间过了period参数指定的时间间隔,再次开启任务去执行.

  - scheduleAtFixedRate(TimerTask task, Date when, long period) : 在指定的具体时间开始执行某一任务,执行完毕后,一旦时间过了period参数指定的时间间隔,再次开启任务去执行.

  - cancel() : 取消定时器</font>

- Calendar 3个类

  - Calendar.getInstance() : 获取日历对象

  - Calendar.get(int field) : 获取具体字段的值 , 注意month字段是从0开始的

  - Calendar.set(int field, int value) : 设置具体某一字段的值

  - Calendar.getTime() : 获取当前时间的Date对象

5 邮件相关概念

- 邮件服务器 : 负责电子邮件收发管理的设备

- 电子邮箱 : 在邮件服务器上开辟一块空间给用户, 用于收发邮件

- 常见邮件协议

  - POP3 : Post Office Protocol - Version 3,邮局协议版本3, 用于接收邮件

  - SMTP : Simple Mail Transfer Protocol,简单邮件传输协议, 用于发送邮件

  - IMAP : Internet Mail Access Protocol,Internet邮件访问协议, 用于接收邮件

- 收发邮件的原理

1 邮件客户端的使用

- 收发邮件的方式

  - 网页

  - Outlook客户端

  - Foxmail客户端

邮件服务器的搭建

- 安装易邮客户端和FoxMail客户端

- 配置易邮客户端

2 Java发送邮件的API(了解)

- Java Mail

- 导入JAR包

- 调用API.三个核心类

Filter接口的方法:3

- Filter也称之为过滤器

- 通过它可以对web服务器管理的所有web资源进行拦截,从而实现特殊控制功能.例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能

init(FilterConfig config):初始化操作

doFilter(ServletRequest request, ServletResponse response, FilterChain chain):处理业务逻辑

destroy() :销毁操作

1 filter的生命周期(了解)

filter单实例多线程  和servletContext 一样生命周期  

生成   filter在服务器启动的时候 服务器创建filter 调用init方法 实现初始化操作

中间执行 请求来的时候,创建一个线程 根据路径调用dofilter 执行业务逻辑

销毁 当filter被移除的时候或者服务器正常关闭的时候 调用destory方法 执行销毁操作.

2 FilterChain:过滤链

通过chain的dofilter方法,可以将请求放行到下一个过滤器,直到最后一个过滤器放行才可以访问到servlet|jsp doFilter()放行方法

★url-pattern配置

- 配置过滤器进行过滤时,除了使用<url-pattern>之外,也可以使用<servlet-name>标签,但是对应的servlet也必须在web.xml中配置.

- <dispatcher> 指定过滤器拦截目标资源的调用方式

3种

完全匹配 必须以"/" 开始  例如: /a/b

目录匹配 必须以"/" 开始 以"*"结束  例如:/a/b/*

后缀名匹配 以"*."开始 以字符结束   例如 :  *.jsp  *.do  *.action

例如:

afilter  路径  /*

bFilter  路径  /demo4

★一个资源有可能被多个过滤器匹配成功,多个过滤器的执行顺序是按照web.xml中filter-mapping的顺序执行的

3.0visiont版本的时候  如果使用的是注解,执行的顺序是类名的字母排列顺序

使用步骤

1对于链接方式 四种调用方式 针对的4中拦截方式  

- REQUEST : 客户端请求过滤(实际开发中一般使用该默认方式)

- FORWARD : 转发过滤

- INCLUDE : 包含过滤

- ERROR : 错误页面过滤 web.xml 配置error-page

- 如果没有指定拦截模式,默认拦截REQUEST

实现业务逻辑

3 FiltConfig

步骤分析:

都是使用 doFilter 进行业务处理过后再返回给 httprequest

1.数据库和表

create database day16;

use day16;

create table user(

id int primary key auto_increment,

username varchar(20),

password varchar(20)

);

insert into user values(null,'tom','123');

2.web项目

jar包 工具类 配置文件

3.新建一个登录页面 表单

4.表单提交 loginservlet

接受用户名和密码

调用service完成登录操作,返回值User

判断user是否为空

若不为空,将user放入session中

判断是否勾选了自动登录

若勾选了:

需要将用户名和密码写回浏览器

5.下次访问网站的时候

过滤器拦截任意请求

判断有无指定的cookie

有cookie,获取用户名和密码

调用service完成登录操作,返回user

当user不为空的时候将user放入session中.

当我们换用jack登录的时候发现登录不了

自动登录只需要登录一次:当session中没有用户的时候

访问有些资源是不需要自动登录的(和登录还有注册相关的资源)

修改filter的逻辑:

首先判断session中是否有user

若没有 并且访问的路径不是和登录注册相关的时候

才去获取指定的cookie

filter总结

filterConfig:(了解)

过滤器的配置对象

作用:

获取全局管理者

获取当前filter的名称

获取当前filter的初始化参数

filter-mapping的子标签(理解)

servlet-name:匹配那个servlet 值写的是serlvet标签中servlet-name的值

建议:不要在一个filter中重复的匹配servlet

例如: serlvet的url-pattern为  /a/b/hello   serlvetname:HelloServlet

如果filter中的url-pattern  /*

最好不要在写 servlet-name:HelloServlet

dispatcher:

匹配哪种请求

默认的是REQUEST,一旦显式的写出来哪种请求,默认就不起作用了

理解

REQUEST:从浏览器发送过来的请求(默认) 理解

FORWARD:转发过来的请求 理解

了解

ERROR:因服务器错误而发送过来的请求

INCLUDE:包含过来的请求

4 案例2-统一字符编码

需求:

以前我们开发的时候若有参数,第一步都是设置编码,才不会出现乱码,通过过滤器设置,到servlet或者jsp上的时候已经没有乱码问题

技术分析:

filter 配置路径/* 过滤器的第一个位置

在filter中重写getParameter(加强)

步骤分析:

我们只需要在filter中 对request进行加强(例如:只对request.getParameter()进行加强)

方法加强:

1.继承(获取构造器)

2.装饰者模式(静态代理)

3.动态代理

装饰者书写步骤:

1.要求装饰者和被装饰者实现同一个接口或者继承同一个类

2.装饰者中要有被装饰者的引用

3.对需要加强方法进行加强

4.对不需要加强的方法调用原来的方法即可

加强request.getParameter(String key)

首先请求的方式不同,处理的方式也不同

获取请求的方法

若是get请求

new String(value.getBytes("iso8859-1"),"utf-8");

若是post请求

只需要设置一句话

request.setCharacterEncoding("utf-8");

最后将包装过的request对象(MyRequest)传递给servlet即可

 关于获取参数的方法

String getParameter(String name);// arr[0]

String[] getParameterValues(String name);// map.get(name)

Map<String,String[]> getParameterMap();

21注解/代理模式/类加载器

1注解:

定义 : Annotation. 也叫元数据.一种代码级别的说明. 它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次. 它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释

jdk5之后提供了一个特性,和类 接口同级

格式: @interface 注解名{}

作用:编译检查 替代配置文件  定义注解(元注解:注解上的注解)  分析代码(用到反射)

1 java中3个注解(理解)

@Override:声明该方法是从分类上继承过来的,执行编译期的检查

@SuppressWarnings:抑制警告 值有好多,只需要知道一个 all  抑制所有的警告

@Deprecated:声明 该方法不赞成使用

2 自定义注解(理解)

注解属性:

注解本质就是一个接口,接口中可以有常量和抽象方法

抽象方法在注解中就称之为注解属性

注解属性类型:

基本类型,String ,Class ,Annotation ,Enum:枚举 以上类型对应的一维数组

注意:一旦注解有属性了,使用注解的时候必须赋值,(除非这个注解属性有默认值)

3 赋值的格式:

@注解名(属性名=属性值)

若注解类型为数组,且只有一个值的时候,可以有两种写法

方式1:

属性名 = { 值 }

方式2:

属性名=属性值

若属性名为value的时候,且只需要为这个value属性赋值的时候,value可以省略

4 元注解:(理解)

定义在注解上的注解

@Retention  规定注解保留到什么阶段  值为RetentionPolicy的三个枚举值

SOURCE:只在代码中保留,在字节码文件中就删除了

CLASS:在代码和字节码文件中保留

RUNTIME:所有阶段都保留

@Target 规定注解作用在什么上面 值为ElementType的枚举值

TYPE:作用在类 接口 等上面

METHOD:作用方法上面

FIELD:作用字段上面

步骤分析:(了解)

1.定义一个注解 @MyTest

2.在一个测试类 MyTestTest 上的添加几个方法

在方法上添加@MyTest

3.在另一个有主方法的类上添加main方法

运行main方法的时候,需要将带有 @MyTest注解的方法执行

案例扩展:

获取连接的工具类,通过配置四个参数

步骤分析:

1.自定义一个注解JDBCInfo

添加元注解:

在程序运行的时候使用  @Retention

只能作用在方法上   @Target

添加注解属性

String driverClass() default "com.mysql.jdbc.Driver";

String url();

String username() default "root";

String password();

2.在jdbcutils工具类中提供一个getConnection,在方法上面添加一个注解 @JDBCInfo(...)

getConnection方法需要进行的操作:获取注解上的四个属性值

获取字节码文件

获取该方法上的注解

获取注解的值

3.运行的时候可以通过getConnection获取一个连接

servlet3.0区别

3.0支持注解开发,没有web.xml这个文件了

内嵌了文件上传功能

例如:

创建servlet 在类上面添加 @WebServlet(urlPatterns={ "/demo2", "/demo21" },loadOnStartup=2)

创建listener 在类上添加 @WebListener

创建filter 在类上添加 @WebFilter(urlPatterns="/*")

文件上传

浏览器端的要求:

表单的提交方法必须是post

必须有一个文件上传组件  <input type="file" name=""/>

必须设置表单的enctype=multipart/form-data

服务器端的要求:

servlet3.0中

需要在servlet中添加注解

@MultipartConfig

接受普通上传组件 (除了文件上传组件):request.getParameter(name属性的值)

接受文件上传组件 request.getPart(name属性的值);

getName():获取的name的属性值

获取文件名:

 part.getHeader("Content-Disposition"):获取头信息 然后截取

上传注意的问题:

名字重复 随机名称

在数据库中提供两个字段,

一个字段用来存放文件的真实名称  1.jpg

另一个字段用来存放文件存放路径  g:/sdfasdf.jpg

随机名称:

uuid

时间戳

文件安全

重要的文件存放在 web-inf 或者 meta-inf 或者 服务器创建一个路径

不是很重要的文件 项目下

文件存放目录

方式1:日期

方式2:用户

方式3:文件个数

方式4:随机目录

mkdirs

2类加载器:(了解)

类加载:

我们编写的.java文件,jvm会将变成.class文件.该文件要想运行,必须加载内存中,然后会生成一个对象.Class对象

类加载器层次结构

引导类加载器 rt.jar

扩展类加载器 ext/*.jar

应用类加载器 我们自己编写类

- Bootstrap ClassLoader : 将jre\lib目录下的类库加载到虚拟机内存中,用来加载java的核心库,不能被java程序直接调用,代码是使用C++编写的.是虚拟机自身的一部分

- Extension ClassLoader : 加载jre\lib\ext目录下的类库,用来加载java的扩展库,开发者可以直接使用这个类加载器.

- App ClassLoader : 加载我们编写的java类,以及第三方的jar

- Custom ClassLoader : 自定义的类加载器,以满足特殊的需求,如tomcat就根据J2EE规范自行实现ClassLoader

全盘负责委托机制:

当一个类运行的时候,有可能有其他类,应用类加载器询问扩展类加载器:你加载过这些类吗?

扩展类加载器在向上问(引导类加载器):你加载过这些类吗?

引导类加载器:我查查,有一个是我负责,我加载.

扩展类加载器:接下来我来查,有几个是我负责,我加载,还有几个类我已经加载完成了,你可以直接使用

应用类加载器:收到了 剩下的我来

3代理模式 统一编码

1 静态代理步骤:

1.要求 被装饰者和 装饰者实现同一个接口或者继承同一个类  只增强接口或者父类中的方法

2.在装饰者中要有被装饰者的引用

3.对需要加强的方法进行加强

4.对不需要加强的方法调用原来的方法

2 动态代理:

Httpservletrequest extent servletrequest   现在实现的方法是 getParameter()这个方法  这个方法首先是父接口的方法   还要有代理对象(下面要用到代理对象)

前提条件  // 动态代理 : 在内存中创建一个原对象的代理对象,原对象所有方法的执行都由代理对象来执行

          // 如果要使用动态代理,那么原对象一定要实现接口,或者继承接口(说明自己也是一个接口)

动态的在内存中创建一个代理对象

Object Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

参数说明:

ClassLoader: 代理对象类加载器 一般我们使用的是被代理对象的类加载器

Class[]:   代理对象需要实现接口 一般我们使用的是被搭理对象所实现的所有接口

InvocationHandler:  执行处理类.在这里面对方法进行加强

invocationHandler中只有一个方法

Object invoke(Object proxy, Method method, Object[] args)

l 参数说明:

n // 原对象所有方法的执行,都由下面的invoke方法来决定

n // 参数1 : 就是代理对象本身.但是实际开发中,不会使用这个对象 因为访问不到会出现空指针

n // 参数2 : 方法.就是原对象的所有方法

n // 参数3 : 参数.就是原对象所对应的实参

l 返回值:就是当前method对象执行的返回值

写完过后把这个对象 传输下去  以后执行的时候变成了代理对象  proxy执行

proxy.sleep(5);

 步骤分析:

过滤器

doFilter(Request request,Response response)

将代理request传递过去

doFilter(Request requestPrxoy,Response response)

对于这个request 后面只要过一下 这个设置编码的 就行  到下面再把这个运行的方法 返回出去

else if ("post".equalsIgnoreCase(method2)) {

request.setCharacterEncoding("utf-8");

}

}

return method.invoke(request, args);

发布了38 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/sdrfengmi/article/details/79157042