JavaWeb----JDBC/Servlet/MVC/三层/分页/过滤器/监听器/Ajax

目录

1.JDBC

2.JDBC API 主要功能:

3.jdbc访问数据库的具体步骤:

4.数据库驱动

1.jdbc总结(模板、八股文):

2.CallableStatement:调用 存储过程、存储函数

3.处理CLOB/BLOB类型

1.jdbc总结(模板、八股文):

2.CallableStatement:调用 存储过程、存储函数

3.处理CLOB/BLOB类型

4.JSP访问数据库

5.JavaBean

MVC设计模式:

1.回顾纯手工方法创建第一个Servlet

2.借助于Eclipse快速生成Servlet

3. 项目根目录:WebContent、src(所有的构建路径)

4.Servlet生命周期:5个阶段

5 Servlet API :

6.Servlet继承关系

三层优化

分页:5变量(属性)

1分页

分页实现:

2表单重复提交

2.EL :为了消除jsp中的Java代码

过滤器:

filter映射

通配符

监听器

session对象  (不需要配置XML)

Ajax


1.JDBC

:Java DataBase Connectivity  可以为多种关系型数据库DBMS 提供统一的访问方式,用Java来操作数据库


2.JDBC API 主要功能:


三件事,具体是通过以下类/接口实现:
DriverManager : 管理jdbc驱动
Connection: 连接(通过DriverManager产生)


Statement(PreparedStatement) :增删改查  (通过Connection产生 )
CallableStatement  : 调用数据库中的 存储过程/存储函数  (通过Connection产生 )

Result :返回的结果集  (上面的Statement等产生 )

Connection产生操作数据库的对象:


Connection产生Statement对象:createStatement()
Connection产生PreparedStatement对象:prepareStatement()
Connection产生CallableStatement对象:prepareCall();

Statement操作数据库:
增删改:executeUpdate()
查询:executeQuery();

ResultSet:保存结果集 select * from xxx
next():光标下移,判断是否有下一条数据;true/false
previous():  true/false
getXxx(字段名|位置):获取具体的字段值 

PreparedStatement操作数据库:
public interface PreparedStatement extends Statement 
因此
增删改:executeUpdate()
查询:executeQuery();
--此外
赋值操作 setXxx();


PreparedStatement与Statement在使用时的区别:
1.Statement:
sql
executeUpdate(sql)

2.
PreparedStatement:
sql(可能存在占位符?)
在创建PreparedStatement 对象时,将sql预编译 prepareStatement(sql)
executeUpdate()
setXxx()替换占位符?

推荐使用PreparedStatement:原因如下:
1.编码更加简便(避免了字符串的拼接)
String name = "zs" ;
int age = 23 ;

stmt:
String sql =" insert into student(stuno,stuname) values('"+name+"',  "+age+" )    " ;
stmt.executeUpdate(sql);

pstmt:
String sql =" insert into student(stuno,stuname) values(?,?) " ;
pstmt = connection.prepareStatement(sql);//预编译SQL
pstmt.setString(1,name);
pstmt.setInt(2,age);


2.提高性能(因为 有预编译操作,预编译只需要执行一次)
需要重复增加100条数 
stmt:
String sql =" insert into student(stuno,stuname) values('"+name+"',  "+age+" )    " ;
for(100)
stmt.executeUpdate(sql);

pstmt:
String sql =" insert into student(stuno,stuname) values(?,?) " ;
pstmt = connection.prepareStatement(sql);//预编译SQL
pstmt.setString(1,name);
pstmt.setInt(2,age);
for( 100){
pstmt.executeUpdate();
}

3.安全(可以有效防止sql注入)
sql注入: 将客户输入的内容  和 开发人员的SQL语句 混为一体

stmt:存在被sql注入的风险  
(例如输入  用户名:任意值 ' or 1=1 --
       密码:任意值)
分析:
select count(*) from login where uname='任意值 ' or 1=1 --' and upwd ='任意值'  ;
select count(*) from login where uname='任意值 ' or 1=1 ;
select count(*) from login ;


select count(*) from login where uname='"+name+"' and upwd ='"+pwd+"' 

pstmt:有效防止sql注入


推荐使用pstmt

3.jdbc访问数据库的具体步骤:


a.导入驱动,加载具体的驱动类
b.与数据库建立连接
c.发送sql,执行
d.处理结果集 (查询)

4.数据库驱动

        驱动jar                    具体驱动类                        连接字符串
Oracle        ojdbc-x.jar                oracle.jdbc.OracleDriver                jdbc:oracle:thin:@localhost:1521:ORCL
MySQL        mysql-connector-java-x.jar        com.mysql.jdbc.Driver                    jdbc:mysql://localhost:3306/数据库实例名
SqlServer    sqljdbc-x.jar                com.microsoft.sqlserver.jdbc.SQLServerDriver        jdbc:microsoft:sqlserver:localhost:1433;databasename=数据库实例名

使用jdbc操作数据库时,如果对数据库进行了更换,只需要替换:驱动、具体驱动类、连接字符串、用户名、密码

1.jdbc总结(模板、八股文):

try{
a.导入驱动包、加载具体驱动类Class.forName("具体驱动类");
b.与数据库建立连接connection = DriverManager.getConnection(...);
c.通过connection,获取操作数据库的对象(Statement\preparedStatement\callablestatement)
stmt = connection.createStatement();
d.(查询)处理结果集rs = pstmt.executeQuery()
while(rs.next()){ rs.getXxx(..) ;}
}catch(ClassNotFoundException e  )
{ ...}
catch(SQLException e)
{...
}
catch(Exception e)
{...
}
finally
{
    //打开顺序,与关闭顺序相反
    if(rs!=null)rs.close()
    if(stmt!=null) stmt.close();
    if(connection!=null)connection.close();
}

--jdbc中,除了Class.forName() 抛出ClassNotFoundException,其余方法全部抛SQLException


2.CallableStatement:调用 存储过程、存储函数


connection.prepareCall(参数:存储过程或存储函数名)
参数格式:
存储过程(无返回值return,用out参数替代):
    { call  存储过程名(参数列表) }
存储函数(有返回值return):
    { ? = call  存储函数名(参数列表) }

create or replace procedure addTwoNum ( num1  in number,num2  in number,result out number )  -- 1 + 2 ->3
as
begin
    result := num1+num2 ;
end ;
/


强调:
如果通过sqlplus 访问数据库,只需要开启:OracleServiceSID
通过其他程序访问数据(sqldevelop、navicate、JDBC),需要开启:OracleServiceSID、XxxListener


JDBC调用存储过程的步骤:
a.产生 调用存储过程的对象(CallableStatement) cstmt =     connection.prepareCall(   "..." ) ;
b.通过setXxx()处理 输出参数值 cstmt.setInt(1, 30);
c.通过 registerOutParameter(...)处理输出参数类型
d.cstmt.execute()执行
e.接受 输出值(返回值)getXxx()


调存储函数:
create or replace function addTwoNumfunction ( num1  in number,num2  in number)  -- 1 + 2 
return number
as
    result number ;    
begin
    result := num1+num2 ;
    return result ;
end ;
/
JDBC调用存储函数:与调存储过程的区别:
在调用时,注意参数:"{? =  call addTwoNumfunction    (?,?) }"


3.处理CLOB/BLOB类型


处理稍大型数据:
    
a.存储路径    E:\JDK_API_zh_CN.CHM
    通过JDBC存储文件路径,然后 根据IO操作处理
    例如:JDBC将 E:\JDK_API_zh_CN.CHM 文件 以字符串形式“E:\JDK_API_zh_CN.CHM”存储到数据库中
        获取:1.获取该路径“E:\JDK_API_zh_CN.CHM”  2.IO    

b.
    CLOB:大文本数据 (小说->数据)
    BLOB:二进制


clob:大文本数据   字符流 Reader Writer

1.先通过pstmt 的? 代替小说内容 (占位符)
2.再通过pstmt.setCharacterStream(2, reader,  (int)file.length());  将上一步的?替换为 小说流, 注意第三个参数需要是 Int类型

取:
1.通过Reader reader = rs.getCharacterStream("NOVEL") ; 将cloc类型的数据  保存到Reader对象中
2. 将Reader通过Writer输出即可。


blob:二进制  字节流 InputStream OutputStream
与CLOB步骤基本一致,区别:setBinaryStream(...)  getBinaryStream(...)   

1.jdbc总结(模板、八股文):

try{
a.导入驱动包、加载具体驱动类Class.forName("具体驱动类");
b.与数据库建立连接connection = DriverManager.getConnection(...);
c.通过connection,获取操作数据库的对象(Statement\preparedStatement\callablestatement)
stmt = connection.createStatement();
d.(查询)处理结果集rs = pstmt.executeQuery()
while(rs.next()){ rs.getXxx(..) ;}
}catch(ClassNotFoundException e  )
{ ...}
catch(SQLException e)
{...
}
catch(Exception e)
{...
}
finally
{
    //打开顺序,与关闭顺序相反
    if(rs!=null)rs.close()
    if(stmt!=null) stmt.close();
    if(connection!=null)connection.close();
}

--jdbc中,除了Class.forName() 抛出ClassNotFoundException,其余方法全部抛SQLException


2.CallableStatement:调用 存储过程、存储函数


connection.prepareCall(参数:存储过程或存储函数名)
参数格式:
存储过程(无返回值return,用out参数替代):
    { call  存储过程名(参数列表) }
存储函数(有返回值return):
    { ? = call  存储函数名(参数列表) }

create or replace procedure addTwoNum ( num1  in number,num2  in number,result out number )  -- 1 + 2 ->3
as
begin
    result := num1+num2 ;
end ;
/


强调:
如果通过sqlplus 访问数据库,只需要开启:OracleServiceSID
通过其他程序访问数据(sqldevelop、navicate、JDBC),需要开启:OracleServiceSID、XxxListener


JDBC调用存储过程的步骤:
a.产生 调用存储过程的对象(CallableStatement) cstmt =     connection.prepareCall(   "..." ) ;
b.通过setXxx()处理 输出参数值 cstmt.setInt(1, 30);
c.通过 registerOutParameter(...)处理输出参数类型
d.cstmt.execute()执行
e.接受 输出值(返回值)getXxx()


调存储函数:
create or replace function addTwoNumfunction ( num1  in number,num2  in number)  -- 1 + 2 
return number
as
    result number ;    
begin
    result := num1+num2 ;
    return result ;
end ;
/
JDBC调用存储函数:与调存储过程的区别:
在调用时,注意参数:"{? =  call addTwoNumfunction    (?,?) }"


3.处理CLOB/BLOB类型


处理稍大型数据:
    
a.存储路径    E:\JDK_API_zh_CN.CHM
    通过JDBC存储文件路径,然后 根据IO操作处理
    例如:JDBC将 E:\JDK_API_zh_CN.CHM 文件 以字符串形式“E:\JDK_API_zh_CN.CHM”存储到数据库中
        获取:1.获取该路径“E:\JDK_API_zh_CN.CHM”  2.IO    

b.
    CLOB:大文本数据 (小说->数据)
    BLOB:二进制


clob:大文本数据   字符流 Reader Writer

a.先通过pstmt 的? 代替小说内容 (占位符)
b.再通过pstmt.setCharacterStream(2, reader,  (int)file.length());  将上一步的?替换为 小说流, 注意第三个参数需要是 Int类型

取:
a.通过Reader reader = rs.getCharacterStream("NOVEL") ; 将cloc类型的数据  保存到Reader对象中
b. 将Reader通过Writer输出即可。

blob:二进制  字节流 InputStream OutputStream
与CLOB步骤基本一致,区别:setBinaryStream(...)  getBinaryStream(...)   


4.JSP访问数据库

JSP就是在html中嵌套的java代码,因此 java代码可以写在jsp中(<%  ... %>)

导包操作:java项目 :1 Jar复制到工程中 2.右键该Jar :build path ->add to build Path
      Web项目:jar复制到WEB-INF/lib

核心:就是将 java中的JDBC代码,复制到 JSP中的<% ... %>


注意:如果jsp出现错误:The import Xxx cannot be resolved
    
尝试解决步骤:
    a.(可能是Jdk、tomcat版本问题) 右键项目->build path,将其中 报错的 libary或Lib 删除后 重新导入
    b.清空各种缓存:右键项目->Clean tomcat... clean  (Project -clean或者 进tomcat目录 删除里面work的子目录)
    c.删除之前的tomcat,重新解压缩、配置tomcat,重启计算机
    d.如果类之前没有包,则将该类加入包中
    

5.JavaBean


刚才我们将 jsp中 登录操作的代码  转移到了LoginDao.java;其中LoginDao类 就称之为JavaBean。
JavaBean的作用:a.减轻的jsp复杂度  b.提高代码复用(以后任何地方的 登录操作,都可以通过调用LoginDao实现)

JavaBean(就是一个Java类)的定义:满足一下2点 ,就可以称为JavaBean
    a.public 修饰的类  ,public 无参构造
    b.所有属性(如果有) 都是private,并且提供set/get   (如果boolean 则get 可以替换成is)

使用层面,Java分为2大类:
a.封装业务逻辑的JavaBean (LoginDao.java封装了登录逻辑)            逻辑
    可以将jsp中的JDBC代码,封装到Login.java类中 (Login.java)

b.封装数据的JavaBean   (实体类,Student.java  Person.java  )        数据 
    对应于数据库中的一张表
    Login login = new Login(uname,upwd) ;//即用Login对象 封装了2个数据(用户名 和密码)

封装数据的JavaBean 对应于数据库中的一张表   (Login(name,pwd))
封装业务逻辑的JavaBean 用于操作 一个封装数据的JavaBean  

可以发现,JavaBean可以简化 代码(jsp->jsp+java)、提供代码复用(LoginDao.java)

public  void sleep(String name,String place, int time)
{

}

public  void sleep(Person per)
{
    per.getName()
    per.getPlace()
    ...
}

MVC设计模式:


M:Model    ,模型  :一个功能。用JavaBean实现。

V:View,视图: 用于展示、以及与用户交互。使用html  js  css jsp jquery等前端技术实现

C:Controller,控制器 :接受请求,将请求跳转到模型进行处理;模型处理完毕后,再将处理的结果
            返回给 请求处 。 可以用jsp实现,  但是一般建议使用 Servlet实现控制器。

Jsp->Java(Servlet)->JSP


Servlet:
Java类必须符合一定的 规范:
    a.必须继承  javax.servlet.http.HttpServlet
    b.重写其中的 doGet()或doPost()方法

 doGet(): 接受 并处 所有get提交方式的请求
 doPost():接受 并处 所有post提交方式的请求


Servlet要想使用,必须配置
Serlvet2.5:web.xml
Servle3.0: @WebServlet


Serlvet2.5:web.xml:

项目的根目录:WebContent 、src

<a href="WelcomeServlet">所在的jsp是在 WebContent目录中,因此 发出的请求WelcomeServlet  是去请求项目的根目录。

Servlet流程:
请求 -><url-pattern> -> 根据<servlet-mapping>中的<servlet-name> 去匹配  <servlet> 中的<servlet-name>,然后寻找到<servlet-class>,求中将请求交由该<servlet-class>执行。

2个/:
jsp:/  localhost:8888
web.xml: /   http://localhost:8888/项目名/

1.回顾纯手工方法创建第一个Servlet


步骤:
编写一个类,继承HttpServlet
重写doGet()、doPost()方法
编写web.xml 中的servlet映射关系

2.借助于Eclipse快速生成Servlet


直接新建Servlet即可!(继承、重写、web.xml  可以借助Eclipse自动生成)

Servlet3.0,与Servlet2.5的区别:
Servlet3.0不需要在web.xml中配置,但 需要在 Servlet类的定义处之上编写 注解@WebServlet("url-pattern的值") 
匹配流程:  请求地址 与@WebServlet中的值 进行匹配,如果匹配成功 ,则说明 请求的就是该注解所对应的类

3. 
项目根目录:WebContent、src(所有的构建路径)


例如:
WebContent中有一个文件index.jsp
src中有一个Servlet.java  

如果: index.jsp中请求 <a href="abc">...</a> ,则 寻找范围:既会在src根目录中找  也会在WebContent根目录中找

如果:index.jsp中请求<a href="a/abc"></a>,寻找范围:先在src或WebContent中找a目录,然后再在a目录中找abc

web.xml中的 /:代表项目根路径
http://localhost:8888/Servlet25Project/
jsp中的/: 服务器根路径
http://localhost:8888/

构建路径、WebContent:根目录


4.Servlet生命周期:5个阶段

 
加载
初始化: init()  ,该方法会在 Servlet被加载并实例化的以后 执行
服务  :service() ->doGet()  doPost
销毁  :destroy(),  Servlet被系统回收时执行
卸载


init():
    a.默认第一次访问 Servlet时会被执行 (只执行这一次)
    b.可以修改为 Tomcat启动时自动执行
        i.Servlet2.5:  web.xml
              <servlet>
                ...
                   <load-on-startup>1</load-on-startup>
                </servlet>
            其中的“1”代表第一个。
        ii.Servlet3.0
            @WebServlet( value="/WelcomeServlet" ,loadOnStartup=1  )


service() ->doGet()  doPost :调用几次,则执行几次
destroy():关闭tomcat服务时,执行一次。


5 Servlet API :

由两个软件包组成: 对应于HTTP协议的软件包、对应于除了HTTP协议以外的其他软件包
即Servlet  API可以适用于 任何 通信协议。 
我们学习的Servlet,是位于javax.servlet.http包中的类和接口,是基础HTTP协议。

6.Servlet继承关系

ServletConfig:接口 
ServletContext getServletContext():获取Servlet上下文对象   application
String  getInitParameter(String name):在当前Servlet范围内,获取名为name的参数值(初始化参数)

a.ServletContext中的常见方法(application):
getContextPath():相对路径
getRealPath():绝对路径
setAttribute() 、getAttribute()
--->
String getInitParameter(String name);在当前Web容器范围内,获取名为name的参数值(初始化参数)

Servlet3.0方式 给当前Servlet设置初始值:
@WebServlet( .... , initParams= {@WebInitParam(name="serveltparaname30",value="servletparavalue30")   }   )
注意,此注解只 隶属于某一个具体的Servlet ,因此无法为 整个web容器设置初始化参数 (如果要通过3.0方式设置 web容器的初始化参数,仍然需要在web.xml中设置)

HttpServletRequest中的方法:(同request),例如setAttrite()、getCookies()、getMethod()
HttpServletResponse中的方法:同response

Servlet使用层面:

Eclipse中在src创建一个Servlet,然后重写doGet()  doPost()就可以  (doGet() doPost()只需要编写一个)。

三层优化


1.加入接口
    建议面向接口开发:先接口-再实现类
    --service、dao加入接口
    --接口与实现类的命名规范
        接口:interface,    起名   I实体类Service        IStudentService
                        IStudentDao    
        实现类:implements    起名   实体类ServiceImpl        StudentServiceImpl
                        StudentDaoImpl
        接口:    I实体类层所在包名    IStudentService、IStudentDao    
            接口所在的包:  xxx.service        xx.dao

        实现类:     实体类层所在包名Impl    StudentServiceImpl、StudentDaoImpl
            实现类所在的包:xxx.service.impl        xx.dao.impl

    以后使用接口/实现类时,推荐写法:
    接口 x = new 实现类();
    IStudentDao studentDao = new StudentDaoImpl();

2.DBUtil 通用的数据库帮助类,可以简化Dao层的代码量

帮助类 一般建议写在  xxx.util包


A
{

    a(){
        B.connection
    }
}

B
{
    static Connection connection =..
    b{
        
    }
}

方法重构:  将多个方法 的共同代码 提炼出来,单独写在一个方法中,然后引入该方法即可
a()
{
    ..
    c();
    ..
    
}

b()
{
    ..
    c();
    ..
}

c()
{
        [..
    ..    
    ...        
    ..]
}


Web调试:
与java代码的调试 区别:启动方式不同

index.jsp ->index_jsp.java ->index_jsp.class 

jsp->java->class
jsp翻译成的Java 以及编译后的class文件 存在于tomcat中的work目录中


10000

分页:5变量(属性)

1.数据总数 (select count(*) from xxx ,          查数据库)
2.页面大小(页面容量,每页显示的数据条数)    (用户自定义)
3.总页数                       (自动计算)
    800:10= 80页
    总页数= 数据总数 /页面大小

    802:10=  800/10 +1 ;
    总页数= 数据总数 /页面大小 + 1;

    -->通式
    总页数= 数据总数 % 页面大小==0 ?数据总数 /页面大小:数据总数 /页面大小 + 1;

注意:自动计算的时机:当 数据总数 和 页面大小都被赋值以后,自动计算总页数。


4.当前页码                    (用户自定义)

5.实体类对象集合(当前页的数据集合):依赖于数据库     (查数据库)
    假设: 每页显示10条(页面大小=10)

select * from student where id>=起始 and id<=终止;


页数          起止            起止等价写法
1        1-10            (页数-1)*10+1-页数*10
2        11-20
3        21-30


某一页的数据 起止:

    (页数-1)*10+1-页数*10

select * from student where sno>=(页数-1)*10+1 and sno<=页数*10;
此种分页SQL 严格依赖sno的数据,  一旦sno出现了间隙(裂缝),则无法满足每页10条

->将此SQL 转换: 1.有rownum  2不能有rownum>xx
转换的核心:  将rownum从伪列 转换为 一个 临时表的 普通列。

select *from 
(
    select rownum r,t.*from
    (select s.* from student s order by sno asc) t   
 
) where r>=(页数-1)*10+1 and r<=页数*10;            


优化:

select *from (
    select rownum r,t.*from
    (select s.* from student s order by sno asc) t
    where      rownum<=页数*页面大小            
 
) where  r>=(页数-1)*页面大小+1     ;                
 

dao和DBUtil的区别:
dao 是处理特定 类的 数据库操作类:
DBUtil是通用  数据库操作类

1分页


要实现分页,必须知道  某一页的 数据 从哪里开始 到哪里结束

页面大小:每页显示的数据量

假设每页显示10条数据

mysql分页:
mysql:从0开始计数
0        0        9
1        10        19
2        20        29
n        n*10          (n+1)*10-1

结论:
分页:
    第n页的数据:  第(n-1)*10+1条  -- 第n*10条

MYSQL实现分页的sql:
limit  开始,多少条
第0页
select * from student limit 0,10 ;
第1页
select * from student limit 10,10 ;
第2页
select * from student limit  20,10 ;
第n页
select * from student limit n*10,10

mysql的分页语句:

select * from student limit 页数*页面大小,页面大小


b.oracle分页:

sqlserver/oracle:从1开始计数
第n页        开始        结束
1        1        10
2        11        20
3        21        30
n        (n-1)*10+1    n*10

select *from student  where sno >=(n-1)*10+1 and sno <=n*10 ;  --此种写法的前提:必须是Id连续 ,否则 无法满足每页显示10条数据


select rownum,t.*from student t where rownum >=(n-1)*10+1 and rownum <=n*10  order by sno;
--1.如果根据sno排序则rownum会混乱(解决方案:分开使用->先只排序,再只查询rownum) 2.rownum不能查询>的数据 

select s.* from student s order by sno asc;


select rownum, t.* from
(select s.* from student s order by sno asc) t 
where rownum >=(n-1)*10+1 and rownum <=n*10 ; ;


//ORACLE\sqlserver都是从1开始计数:  (n-1)*10+1    ---  n*10 
oracle的分页查询语句:
select *from 
(
    select rownum r, t.* from
    (select s.* from student s order by sno asc) t         10000
)
where r>=(n-1)*10+1 and <=n*10  ;                10

优化:

select *from 
(
    select rownum r, t.* from
    (select s.* from student s order by sno asc) t         
    where rownum<=n*10 
)
where r>=(n-1)*10+1  ;    

select *from 
(
    select rownum r, t.* from
    (select s.* from student s order by sno asc) t         
    where  rownum<=页数*页面大小 
)
where r>=(页数-1)*页面大小+1  ;    


SQLServer分页:  3种分页sql
row_number()    over(字段) ;

sqlserver2003:top  --此种分页SQL存在弊端(如果id值不连续,则不能保证每页数据量相等)
select top 页面大小 * from student where id not in 
( select top (页数-1)*页面大小 id from student  order by sno asc )

sqlserver2005之后支持:
select *from 
(
    select row_number()  over (sno order by sno asc) as r,* from student
            
     where r<=n*10 
)
where r>=(n-1)*10+1 and  ;    

SQLServer此种分页sql与oralce分页sql的区别: 1.rownum  ,row_number()    2.oracle需要排序(为了排序,单独写了一个子查询),但是在sqlserver 中可以省略该排序的子查询  因为sqlserver中可以通过over直接排序


sqlserver2012之后支持:    
offset fetch next only


select * from student  oreder by sno 
offset (页数-1)*页面大小+1  rows fetch next 页面大小  rows only ;


(n-1)*10+1    ---  n*10 

mysql从0开始计数,Oracle/sqlserver 从1开始计数

分页实现:


5个变量(属性)            
1.数据总数    100    103                    (查数据库,select count(*)..)                                    
2.页面大小(每页显示的数据条数)20                  (用户自定义)
3.总页数                              (程序自动计算)
    总页数 = 100/20  =数据总数/页面大小
    总页数 = 103/20 = 数据总数/页面大小+1
    --->
    总页数 = 数据总数%页面大小==0? 数据总数/页面大小:数据总数/页面大小+1 ;

                                    
4.当前页(页码)                              (用户自定义)                                
5.当前页的对象集合(实体类集合):每页所显示的所有数据 (10个人信息)
List<Student>                               (查数据库,分页sql)    
        

    

2表单重复提交

1.下载时 ,文件名乱码问题:
edge:

URLEncoder.encode(fileName,"UTF-8") 

firefox:
给文件名 加:
前缀   =?UTF-8?B?

String构造方法
Base64.encode   
后缀   ?=
示例:
    response.addHeader("content-Disposition","attachment;filename==?UTF-8?B?"+   new String(  Base64.encodeBase64(fileName.getBytes("UTF-8"))  ) +"?=" );//fileName包含了文件后缀:abc.txt
        

2.EL :为了消除jsp中的Java代码

语法:
${EL表达式}
a.EL不需要导包
b.在el中调用属性,其实是调用的getXxx()方法

${范围.对象.属性.属性的属性 }

操作符:操作:属性,不是对象
. : 使用方便
[] : 如果是常量属性,需要使用双引号/单引号 引起来;比点操作符更加强大


[]强大之处:
a.可以容纳一些 特殊符号 (.  ?   -)
b.[]可以容纳 变量属性 (可以动态赋值)
String x = "a";
${requestScope.a}等价于${requestScope["a"]}等价于${${requestScope[x]}

c.可以处理数组
${requestScope.arr[0] }

普通对象、map中的变量


通过EL获取JSP  九大内置对象


${pageContext }
${pageContext.request }
${pageContext.sessoin }


JSTL:比EL更加强大
需要引入2个jar :jstl.jar   standard.jar
引入tablib  :
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>    
其中prefix="c" :前缀

核心标签库:  通用标签库、条件标签库  迭代标签库

a.通用标签库
<c:set>赋值
i:
在某个作用域之中(4个范围对象),给某个变量赋值
    <%-- 
        request.setAttribute("name", "zhangsan") ;
    --%>
        <c:set var="name"    value="zhangsan"   scope="request"/>
        ${requestScope.name }

<c:set var="变量名"    value="变量值"   scope="4个范围对象的作用域"/>


ii:
给普通对象赋值
在某个作用域之中(4个范围对象),给某个对象的属性复制 (此种写法,不能指定scope属性)

        <c:set target="${requestScope.student}" property="sname"  value="zxs" />

给map对象赋值
        <c:set target="${requestScope.countries}" property="cn"  value="中国" />

<c:set target="对象" property="对象的属性"  value="赋值" />
        

注意 <c:set>可以给不存在的变量赋值 (但不能给不存在的对象赋值)

<c:out>  :显示
true:<c:out value='<a href="https://www.baidu.com">百度</a>' default="当value为空的,显示的默认值" escapeXml="true" />
false:    <c:out value='<a href="https://www.baidu.com">百度</a>' escapeXml="false" />
        


<c:remove >:删除属性
<c:remove var="a" scope="request"/>


选择:
if(boolean)
单重选择
<c:if test="" >


if else if... esle if... else  /switch
  
<c:choose>
    <c:when test="...">   </c:when>
    <c:when test="...">   </c:when>
    <c:when test="...">   </c:when>
    <c:otherwise>   </c:otherwise>
</c:choose>


在使用 test="" 一定要注意后面是否有空格
例如:test="${10>2 }"   true
     test="${10>2 } "  非true


循环(迭代标签库)
for(int i=0;i<5;i++)
    <c:forEach  var="name" items="${requestScope.names }" >
        -${name }-
    </c:forEach>


for(String str:names)
    <c:forEach  var="student" items="${requestScope.students }" >
        ${student.sname }-${student.sno }
    
    </c:forEach>

过滤器:


实现一个Filter接口
init()、destroy() 原理、执行时机 同Servlet
配置过滤器,类似servlet
通过doFilter()处理拦截,并且通过chain.doFilter(request, response);放行


filter映射

只拦截 访问MyServlet的请求
    <url-pattern>/MyServlet</url-pattern>
拦截一切请求(每一次访问 都会被拦截)
<url-pattern>/*</url-pattern>


通配符

dispatcher请求方式:
REQUEST:拦截HTTP请求 get post
FORWARD:只拦截 通过 请求转发方式的请求

INCLUDE:只拦截拦截通过 request.getRequestDispatcher("").include()  、通过<jsp:include page="..." />此种方式发出的请求
ERROR:只拦截<error-page>发出的请求


过滤器中doFilter方法参数:ServletRequest
在Servlet中的方法参数:HttpServletRequest


过滤器链
可以配置多个过滤器,过滤器的先后顺序 是由 <filter-mapping>的位置 决定

监听器

实现接口

PageContext
Request:ServletRequestListener;
Session:HttpSessionListener;

application  ServletContextListener;   启动时自动创建

属性变更:ServletContextAttributeListener:增加  替换  删除

session对象  (不需要配置XML)

监听 钝化  活化 HttpSessionActivationListener 

绑定  解绑 HttpSessionBindingListener   session.attribute

钝化活化配置 :超过最大时间陪钝化

Tomcat  context.xml  <Manager  classname="org.apache.catalina.session.PersistentManager" maxIdleSwap="5"/>

<Store classname="org.apache.catalina.session.FileStore" directory="zzw">  //tomcat项目相对路径

本质是序列化和反序列化   活化需要实现接口

Ajax

异步js和xml   异步刷新  

实现: 

js:   XMLHttpRequest对象
XMLHttpRequest对象的方法:
open(方法名(提交方式get|post),服务器地址,true) :与服务端建立连接
send():
    get:    send(null)
    post:    send(参数值)
setRequestHeader(header,value):
    get:不需要设置此方法
    post:需要设置:
        a.如果请求元素中包含了 文件上传:
            setRequestHeader("Content-Type","multipart/form-data");
        b.不包含了 文件上传
            setRequestHeader("Content-Type","application/x-www-form-urlencoded")

XMLHttpRequest对象的属性:
readyState:请求状态   只有状态为4 代表请求完毕
status:响应状态  只有200 代表响应正常
onreadystatechange:回调函数
responseText:响应格式为String
responseXML:相应格式为XML


jquery:推荐
$.ajax({
url:服务器地址,
请求方式:get|post,
data:请求数据,
success:function(result,testStatus)
{

},
error:function(xhr,errrorMessage,e){

}
});
$.get(
服务器地址,
请求数据,
function (result){

},
预期返回值类型(string\xml)
);

$.post(
服务器地址,
请求数据,
function (result){

},
    "xml" 或 "json" 或 "text" 
);

$(xxx).load(
服务器地址,
请求数据
);

load:将服务端的返回值  直接加载到$(xxx)所选择的元素中

$.getJSON(
服务器地址,
JSON格式的请求数据,
function (result){

}

);
 

发布了18 篇原创文章 · 获赞 4 · 访问量 5258

猜你喜欢

转载自blog.csdn.net/Zzw1129/article/details/104330316