JSP

JSP

声明:以下是根据颜群老师的学习视频所做的笔记。

JavaWeb视频教程_

 

1、JSP执行流程

jsp→java(servlet文件)→class

第一次访问:服务端将jsp翻译成java,再将java编译成class文件

第二次访问:直接访问class文件(如果服务端代码修改了,将会再访问时重新翻译、编译)

 

2、使用IDEA开发JSP项目

(1)在IDEA中创建JSP项目

Intellij IDEA2021.1创建Java web项目_

 

(2)统一字符集编码

设置jsp文件的编码(jsp文件中的pageEncoding属性):jsp → java

设置浏览器读取jsp文件的编码(jsp文件中的content属性)

 

(3)IDEA中Tomcat乱码问题

idea tomcat 乱码问题的解决及相关设置

 

(4)热部署设置

  Run → Edit Configurations,进行如下的配置。

 

 

 

 

 

 

 

 

(5)jar包问题

  ①jar包本身只在运行时有效

    处理办法:将jar包复制在Web-Content/lib目录中。

  ②jar包在开发和运行时有效

    处理办法:将jar包复制在Web-Content/lib目录中,并且再复制一份到src目录,并右击再点Add as Library。

 

3、JSP页面元素

(1)脚本Scriptlet

  ①<% 局部变量、java语句 %>

  ②<%! 全局变量、定义方法 %>

  ③<%=输出表达式 %>

 

(2)指令

指令作用
<%@ page ... %> 定义网页依赖属性,比如脚本语言、error页面、缓存需求等等
<%@ include ... %> 包含其他文件
<%@ taglib ... %> 引入标签库的定义

  page指令的属性:

    ①language:jsp页面使用的脚本语言

    ②import:导入类

    ③pageEncoding:jsp文件自身编码

    ④contentType:浏览器解析jsp的编码

 

(3)注释

  ①html注释 <!-- --> 可以通过浏览器查看源代码查看

  ②java注释 // /.../

  ③jsp注释 <%-- --%>

 

4、JSP内置对象

内置对象指自带的,不需要new也能使用的对象。

  ①request(请求对象)      ②response(响应对象)

  ③session(会话对象)      ④application(全局对象)

  ⑤out(输出对象)        ⑥pageContext(JSP页面容器)

  ⑦config(配置对象)         ⑧page(当前JSP页面对象)

  ⑨exception(异常对象)

 

5、内置对象:request

(1)request

  请求对象,存储“客户端向服务端发送的请求信息”。

 

(2)request对象的常见方法

 

(3)请求方法分为get和post,区别如下所示:

  ①get方式在地址栏显示请求信息(但是地址栏能够容纳的信息有限,4-5KB;如果请求数据存在大文件,会导致地址栏无法容纳全部的数据而出错);post不会显示

  ②文件上传操作,必须是post

 

(4)统一请求的编码

  get请求出现乱码,解决方法如下:

    ①统一每一个变量的编码

1 String name = request.getParameter("uname");
2 name = new String(name.getBytes("iso-8859-1"),"utf-8");

 

    ②修改server.xml,一次性的更改tomcat默认get提交方式的编码

1 //增加URIEncodeing属性,指定编码方式
2 <Connector port="8080" protocol="HTTP/1.1"
3                connectionTimeout="20000"
4                redirectPort="8443" URIEncodeing="UTF-8" />

 

  post请求出现乱码,解决方法如下:

    ①在获取数据的页面增加下面代码

1 request.setCharacterEncoding("utf-8");//只对post方式有效

 

6、内置对象:response

响应对象。

(1)response对象的常见方法

方法作用
void addCookie(Cookie cookie) 添加指定的cookie至响应中
void setCharacterEncoding(String charset) 指定响应的编码集(MIME字符集),例如UTF-8
void setContentType(String type) 设置响应的内容的类型,如果响应还未被提交的话
void sendRedirect(String location) 使用指定的URL向客户端发送一个临时的间接响应
void addHeader(String name, String value) 添加指定名称的响应头和值

 

(2)页面跳转方式

1 //重定向:页面跳转,但数据会丢失;地址栏会发生改变
2             //        请求2次,它会将目标页面返回给客户端,客户端再向服务端请求
3 response.sendRedirect("success.jsp");
4             //请求转发:页面跳转,数据不会丢失;地址栏没有改变,仍然保留转发时的页面
5             //         请求1次,服务端内部直接跳转到目标页面
6             request.getRequestDispatcher("success.jsp").forward(request,response);

 

7、Cookie

Cookie不是内置对象,是否服务端生成的,再发送给客户端保存。

Cookie可以提高访问服务端的效率,但是安全性较差。

Cookie对象是由javax.servlet.http.Cookie类产生。

(1)Cookie对象的常见方法

方法作用
public String getName() 返回 cookie 的名称,名称创建后将不能被修改
public String getValue() 获取cookie的值
public void setMaxAge(int expiry) 设置 cookie 有效期,以秒为单位,默认有效期为当前session的存活时间

 

(2)交互

  服务端准备Cookie,并跳转到客户端(重定向和请求转发都可以)。

1 response.addCookie(Cookie cookie);
2 response.sendRedirect("success.jsp");

  客户端获取Cookie,不能直接获取一个单独对象,只能一次性将全部的cookie都拿到。

1 request.getCookies();

 

8、内置对象:session

session指会话,表示从开始到结束。

(1)session机制

  ①session存储在服务端

  ②session是在用一个用户(客户)请求时共享

  ③实现机制:

  客户端第一次访问服务端时,服务端会生成一个session对象(用于保存该客户的信息),并且每个session对象都会有一个唯一的sessionId(用于区分其他session)。服务端会自动产生一个Cookie,并且该Cookie的name=JSESSIONID,value=服务端sessionId的值。然后服务端会在响应客户端的同时,将该Cookie发送给客户端,至此客户端就有了一个Cookie(JSESSIONID)。因此,客户端的Cookie就可以和服务端的session一一对应(JSESSIONID — sessionId)。

  客户端第二/n次请求服务端时:服务端会先用客户端Cookie中的JSESSIONID,去服务端的session中匹配sessionId。如果匹配成功(Cookie JESSIONID 和 session sessionId),说明此用户不是第一次访问,无需再次登录。

 

(2)session的常见方法

方法作用
public String getId() 返回session对象的ID
public boolean isNew() 返回是否为一个新的客户端,或者客户端是否拒绝加入session
public void invalidate() 将session无效化,解绑任何与该session绑定的对象(退出登录、注销)
public void setAttribute(String name, Object value) 使用指定的名称和值来产生一个对象并绑定到session中
public Object getAttribute(String name) 返回session对象中与指定名称绑定的对象,如果不存在则返回null
public void setMaxInactiveInterval(int interval) 设置最大有效非活动时间
public int getMaxInactiveInterval() 获取最大有效非活动时间

 

(3)Cookie和session的区别

  ①保存的位置:session在服务端,Cookie在客户端

  ②安全性:session较安全,Cookie较不安全

  ③保存的内容:session保存Object,Cookie保存String

 

(4)Session对象的四种状态

  ①对象a绑定到session中:session.setAttribute("a",xxx)

  ②对象a从session中解绑:session.removeAttribute("a")

  ③钝化:内存 → 硬盘,将session从内存中取出保存到硬盘

  ④活化:硬盘 → 内存,将session从硬盘中取出保存到内存

 

(5)监听Session对象的状态

  监听绑定和解绑:HttpSessionBingListener

  监听钝化和活化:HttpSessionActivationListener

  绑定和解绑:需要添加的对象实现该HttpSessionBingListener接口,例如session.setAttribute("a",a),a对象应实现该接口。

  这两个监听器不需要配置web.xml。

 

(6)如何钝化、活化

  配置tomcat安装目录/conf/context.xml。钝化和活化的本质就是序列化、反序列化,因此需要实现Serializable接口。

1  <!--通过配置实现钝化、活化 -->
2 <!--maxIdleSwap:最大空闲时间,如果超过该时间将会被钝化
3     FileStore:通过该类具体实现钝化操作-->
4 <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
5     <Store className="org.apache.catalina.session.FileStore" directory="mysession"/>
6 </Manager>

细说Session的钝化和活化及Session的监听器

 

9、内置对象:application

  application是全局对象。当Web服务器启动时,Web服务器会自动创建一个application对象。application对象一旦创建,它将一直存在,直到Web服务器关闭。在整个应用程序的运行过程中只有一个application对象,也即所有访问该网站的客户都共享一个application对象。

(1)application的常见方法

方法作用
String getContextPath() 获取虚拟路径
String getRealPath(String name) 获取绝对路径(name为虚拟路径)

 

10、四种范围对象

范围从小到大:pageContext、request、session、application

(1)对象共有的方法

  ①Object getAttribute(String name);根据属性名获取属性值

  ②void setAttribute(String name,Object obj);设置属性值(新增、修改)

  例如setAttribute(“a”,"b");

    如果a对象之前不存在,则创建一个a对象;如果a对象之前已经存在,则将a的值改为b。

  ③void removeAttribute(String name);根据属性名,删除对象

 

(2)有效范围

  ①pageContext—当前页面有效(页面跳转后无效)

  ②request—同一次请求有效;其他请求无效(请求转发有效;重定向无效)

  ③session—同一次会话有效(无论怎么跳转,都有效;关闭/切换浏览器后无效;从 登录→退出 之间全部有效)

  ④application—全局变量;整个项目运行期间都有效(切换浏览器也有效);关闭服务、其他项目 无效

 

(3)建议

  以上4个对象范围依次增大,尽量使用最小的范围。因为对象的范围越大,造成的性能损耗越多。

 

11、JDBC原理

JDBC可以为多种关系型数据库DBMS提供统一的访问方式,目的是用java操纵数据库。

(1)JDBC概念模型

  ①JDBC API:提供各种操作访问接口,包括Connection、Statement、PreparedStatement、ResultSet

  ②JDBC DriverManager:管理不同的数据库驱动

  ③各种数据库驱动:相应的数据库厂商提供的(第三方公司提供),连接\直接操作数据库

 

(2)JDBC API

  JDBC API的主要功能是与数据库建立连接、发送SQL语句和返回处理结果。

具体是通过以下类/接口实现:

  ①DriverManager:管理JDBC驱动

  ②Connection:连接(通过DriverManager产生)

  ③Statement(PreparedStatement):增删改查(通过Connection产生)

  ④CallableStatement:调用数据中的存储过程/存储函数(通过Connection产生)

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

 

(3)JDBC访问数据库的具体步骤

  ①导入驱动,加载具体的驱动类

  ②与数据库建立连接

  ③发送sql,数据库执行

  ④处理结果集

 1 String url = "jdbc:mysql://localhost:3306/stu";
 2 String username = "root";
 3 String password = "";
 4 Connection conn = null;
 5 Statement st = null;
 6 ResultSet rs = null;
 7  8  9 //1.加载驱动(开发推荐的方式)
10 Class.forName("com.mysql.jdbc.Driver");
11 //2.获取与数据库的链接
12 conn = DriverManager.getConnection(url, username, password);
13 //3.获取用于向数据库发送sql语句的statement
14 st = conn.createStatement();
15 //4.向数据库发sql
16 String sql = "select * from student";
17 rs = st.executeQuery(sql);
18 //5.处理结果集
19 while(rs.next()){
20     String id = rs.getString("id");
21     String name = rs.getString("name");
22     int age = rs.getInt("age");
23     System.out.println(id + "," + name + "," + "age");
24 }
25 //6.关闭,关闭顺序与打开顺序相反
26 rs.close();
27 st.close();
28 conn.close();

 

(4)数据库驱动类

数据库具体驱动类连接字符串
oracle oracle.jdbc.OracleDriver jdbc:oracle:thin:@localhost:1521:ORCL
mysql com.mysql.jdbc.Driver jdbc:mysql://localhost:3306/数据库实例名
SlqSever com.microsoft.sqlserver.jdbc.SQLServerDriver jdbc:microsoft:sqlserver:localhost:1433;databasename=数据库实例名

 

(5)Connection产生操作数据库的对象

  ①产生Statement对象:createStatement()

  ②产生PreparedStatement对象:prepareStatement()

  ③产生CallableStatement对象:prepareCall()

 

(6)Statement操作数据库

  ①增删改:executeUpdate()

  ②查询:executeQuery()

 

(7)PreparedStatement操作数据库

  ①增删改:executeUpdate()

  ②查询:executeQuery()

  ③赋值操作:setXxx()

 

(8)ResultSet保存结果集

  ①next():光标下移,判断是否有下一条数据,返回true/false

  ②previous():光标上移,返回true/false

  ③getXxx(字段名|位置):获取具体的字段值

 

(9)Statement和PreparedStatement区别

  Statement是PreparedStatement的父类,功能上基本相同,但推荐使用PreparedStatement。原因如下:

    ①编码更简单(避免了字符串拼接)

    ②安全(可以有效防止sql注入)

1 select count(*) from users where uname='任意' or 1=1 -- ' and pwd='任意';
2 //该语句一直为真,因为or始终未true,而--后面为注释
3 //在输入用户名时直接输入  任意' or 1=1 --

    ③提高性能(PreparedStatement会预编译,只需编译一次,而可以多次执行;Statement每次执行前都要编译)

 1 //Statement
 2 String name = 'Yu';
 3 Statement st = = conn.createStatement();
 4 String sql = "select * from users where uname ='" + name + "'";
 5 st.executeQuery(sql);
 6  7 //PreparedStatement
 8 String sql2 = "select * from users where uname=?";
 9 PreperedStatement st2 = conn.preparedStatement(sql2);//预编译
10 st2.setString(1, name);
11 st2.executeQuery();

 

(10)JDBC调用存储过程和存储函数

  connection.prepareCall(参数:存储过程或存储函数名)

  ①存储过程(无返回值return,用out参数替代)

    参数格式:{ call 存储过程名(参数列表) }

 1 //SQL创建存储过程
 2 create or replace procedure addTwoNum(num1 in number,num2 in number,result out number)
 3 as
 4 begin
 5 result:num1 + num2;
 6 end;/
 7 //JDBC调用存储过程
 8 CallableStatement cstmt = connection.prepareCall("{ call addTwoNum(?,?,?)}");
 9 cstmt.setInt(1,3);
10 cstmt.setInt(2,3);
11 cstmt.registerOutParameter(3,Types.INTEGER);//设置输出参数的类型
12 cstmt.execute();//num1 + num2
13 int result = cstmt.getInt(3);//获取计算结果

 

  ②存储函数(有返回值return)

    参数格式:{ ? = call 存储函数名(参数列表) }

 1 //SQL创建存储函数
 2 create or replace function addTwoNumfunction(num1 in number,num2 in number)
 3 return number
 4 as
 5     result number;
 6 begin
 7     result:=num1 + num2;
 8     return result;
 9 end;/
10 //JDBC调用存储函数
11 CallableStatement cstmt = connection.prepareCall("{ ? = call addTwoNumfunction(?,?)}");
12 cstmt.setInt(2,3);
13 cstmt.setInt(3,3);
14 cstmt.registerOutParameter(1,Types.INTEGER);//设置输出参数的类型
15 cstmt.execute();//num1 + num2
16 int result = cstmt.getInt(1);//获取计算结果

 

12、JDBC处理CLOB及BLOB类型数据

CLOB:大文本数据(小说→数据),Oracle是CLOB,在mysql是Text

BLOB:二进制

 1 //存储CLOB类型的数据
 2 String sql = "insert into novels values(?,?)";
 3 PreperedStatement st = conn.preparedStatement(sql);
 4 st.setInt(1,1);
 5 File file = new File("D:\\novel.txt");
 6 InputStream in = new FileInputStream(file);
 7 Reader reader = new InputStreamReader(in,"GBK")//转换流可以设置编码
 8 st.setCharacterStream(2,reader,file.length());
 9 st.executeUpdate();
10 //读取CLOB类型的数据
11 String sql = "select NOVEL from novels where id=?";
12 PreperedStatement st = conn.preparedStatement(sql);
13 st.setInt(1,1,);
14 ResultSet rs = st.executeQuery();
15 if(rs.next()){
16     Reader reader = rs.getCharacterStream("NOVEL");
17     Writer writer = new FileWriter("src/novel.txt");
18     char[] chs = new char[100];
19     int len = -1;
20     while((len = reader.read(chs))!=-1){
21         writer.write(chs,0,len);
22     }
23     writer.close();
24     reader.close();
25 }
26 
27 //存储BLOB类型的数据
28 String sql = "insert into music values(?,?)";
29 PreperedStatement st = conn.preparedStatement(sql);
30 st.setInt(1,1);
31 File file = new File("D:\\music.mp3");
32 InputStream in = new FileInputStream(file);
33 st.setBinaryStream(2,in,file.length());
34 st.executeUpdate();
35 //读取BLOB类型的数据
36 String sql = "select msc from music where id=?";
37 PreperedStatement st = conn.preparedStatement(sql);
38 st.setInt(1,1,);
39 ResultSet rs = st.executeQuery();
40 if(rs.next()){
41     InputStream in = rs.getBinaryStream("msc");
42     OutputStream out = new FileOutputStream("src/mus.mp3");
43     byte[] chs = new byte[100];
44     int len = -1;
45     while((len = in.read(chs))!=-1){
46         out.write(chs,0,len);
47     }
48     out.close();
49     in.close();
50 }

 

13、JSP访问数据库

在JSP的<% %>中写JDBC语句。

(1)JavaBean定义

  一般会将JSP的<% %>中的操作数据的代码写到一个java文件中,这个类称为JavaBean。

  定义:满足以下两点,就可以称为JavaBean

    ①public修饰的类,public无参构造

    ②所有属性都是private,并且提供set/get(如果boolean,则get可替换is)

 

(2)JavaBean的作用

  ①减轻JSP的复杂度

  ②提高代码的复用率

 

(3)JavaBean分类

  ①封装业务逻辑的JavaBean(LoginDao.java)

    用于操作数据库,对应一个封装数据的JavaBean

  ②封装数据的JavaBean(实体类,Student.java)

    对应数据库中的一张表

  注意:有时候会出现java.lang.ClassNotFoundException: com.mysql.jdbc.Driver错误,此时要么你没有将jar包导入项目,要么就是你的jar包没有放入tomcat的lib目录而导致无法识别。

 

14、MVC设计模式

MVC设计模式一般指MVC框架。经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。

  ①Model:模型,代表一个功能。用JavaBean实现。

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

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

 

15、Servlet

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器。必须符合一定的规范:

  ①必须继承javax.servlet.http.HttpServlet

  ②重写其中的doGet()(接受并处理所有get提交方式的请求)或doPost()(接受并处理所有post提交方式的请求)方法

(1)Servlet创建和配置

Intellij idea创建javaWeb以及Servlet简单实现

 

(2)Servlet部署与流程

请求 → 被相应的<url-pattern>拦截 → 根据<servlet-mapping>中的<servlet-name> 去匹配<servlet>中的<servlet-name> → 寻找到<servlet-class> →将请求交给该<servlet-class>执行。

 1 <servlet>
 2         <servlet-name>WelcomeServlet</servlet-name>
 3         <servlet-class>com.my.servlets.WelcomeServlet</servlet-class>
 4         <load-on-startup>1</load-on-startup>
 5     </servlet>
 6  7     <servlet-mapping>
 8         <servlet-name>WelcomeServlet</servlet-name>
 9         <url-pattern>/servlets/WelcomeServlet</url-pattern>
10     </servlet-mapping>
11 12 <url-pattern>存放请求发起时的位置
13 <servlet-class>Servlet存放的位置
14 <load-on-startup>当有多个Sevlet需要启动时,如果是1,则该Servlet先启动

 

(3)Servlet3.0及以上版本

  Servlet3.0及以上版本不需要在web.xml中配置,但需要在Servlet类的定义处之上编写注解@WebServlet(“url-pattern的值”)。

  匹配流程:请求地址与@WebServlet中的值进行匹配。如果匹配成功,则说明请求的就是该注解所对应的类。

 

(4)项目根目录问题

  项目根目录:Web(在Eclipse中是WebContent)、src

  例如:

    Web中有一个index.jsp文件,src中有一个WelcomeServlet.java文件。

      ①如果index.jsp中请求<a href="WelcomeServlet"/>,寻找范围:在Web和src目录中寻找WelcomeServlet文件

      ②如果index.jsp中请求<a href="servlets/WelcomeServlet"/>,寻找范围:先在Web和src目录中寻找servlets目录,再在该目录寻找WelcomeServlet文件

 

(5)Servlet生命周期

  ①加载

  ②初始化:init(),该方法会在Servlet被加载并实例化以后执行

  ③服务:service() → doGet()、doPost()

  ④销毁:destroy(),Servlet被系统回收时执行

    init():第一次访问Servlet时被执行(只执行一次)

    service() :调用几次,则执行几次

 

(6)Servlet参数值

 1 //1、Servlet2.0方式
 2  <servlet>
 3         <servlet-name>WelcomeServlet</servlet-name>
 4         <servlet-class>com.my.servlets.WelcomeServlet</servlet-class>
 5         <init-param>
 6             <param-name>WelcomeServletParamName</param-name>
 7             <param-value>WelcomeServletParamValue</param-value>
 8         </init-param>
 9 </servlet>
10 //2、Servlet3.0方式
11 @WebServlet(value = "/servlets/WelcomeServlet2",loadOnStartup = 2,initParams = {@WebInitParam(name="WelcomeServlet2Name",value="WelcomeServlet2Value")})
12 //3、设置全局参数
13 <context-param>
14      <param-name>globalParamName</param-name>
15      <param-value>globalParamValue</param-value>
16 </context-param>
17 //4、在Servlet方法中获取参数
18 String value = super.getInitParameter("WelcomeServletParamName");
19         System.out.println("当前Servlet的参数:" + value);
20 ServletContext context = super.getServletContext();
21 String globalValue = context.getInitParameter("globalParamName");
22 System.out.println("全局Servlet的参数:" + globalValue);

 

(7)Servlet中获取对象

1 //1、out
2 PrintWriter out = response.getWriter();
3 //2、session
4 HttpSession session = request.getSession();
5 //3、application
6 ServletContext context = request.getServletContext();

 

16、三层架构

目标是为了解耦合、提高代码复用。

(1)三层组成

  ①表示层(USL,User Show Layer:视图层)

    —前台:对应于MVC中的View,用于与用户交互、界面的显示

        JSP、JS、HTML、CSS、Jquery等web前端技术

    —后台:对应于MVC中的Controller,用于控制跳转、调用业务逻辑层

        Servlet(SpringMVC Struts2)

  ②业务逻辑层(BLL,Business Logic Layer:Service层)

    —接受表示层的请求调用

    —组装数据访问层,逻辑性的操作(增:查+增;删:查+删;改:查+改;查)

  ③数据访问层(DAL,Data Access Layer:Dao层)

    —直接访问数据库的操作,原子性的操作(增删改查)


17、三层优化

(1)加入接口

  建议面向接口开发:先接口,再实现类(service、dao加入接口)

  接口与实现类的命名规范:

    ①接口:interface 起名:I实体类Service IUserService、IUserDao

    ②实现类:implements 起名:实体类ServiceImpl UserServiceImp、UserDapImpl

    ③接口包名:Xxx.service Xxx.dao

    ④实现类包名:Xxx.service.Impl Xxx.dao.Impl

 

 

(2)DBUtil

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

 

18、分页

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

Oracle和SQLServer是从1开始计数的。假设每页可显示10条数据,可知第n页的数据,从第(n-1)*10+1条开始到第n * 10条结束。

第n页         开始          结束
  1           1            10
  2           11           20
  3           21           30
  ...
  n        (n-1)*10+1      n*10 

 

Mysql是从0开始计数的。假设每页可显示10条数据,可知第n页的数据,从第 n10条开始到第 (n+1)10-1 条结束。

第n页            开始            结束
  0              0              9
  1             10             19
  3             20             29
  ...
  n             n*10        (n+1)*10-1 

 

(1)Mysql实现分页的sql

select * from users limit 页数*页面大小,页面大小
--例如第0页
select * from users limit 0,10;

 

(2)Oracle实现分页的sql

--1、在字段存在rownum属性(ROWNUM是一个序列,是oracle数据库从数据文件或缓冲区中读取数据的顺序)可以根据该属性进行筛选
select * from
    (
        select rownum r,t.* from
        (select u.* from users u order by sno asc) t
    )
where r>=(n-1)*10+1 and r<=n*10;
​
优化:
select * from
    (
        select rownum r,t.* from
        (select u.* from users u order by sno asc) t
        where rownum <= n*10
    )
where r>=(n-1)*10+1;

 

(3)SQLServer实现分页的sql

--1、需要使用到row_number() over(字段),表示将表中某一字段作为rownum使用
select * from
    (
        select row_number() over(sno order by sno asc)         as r,t.* from users where r <= n*10
    )
where r>=(n-1)*10+1;
​
--2、top(如果id不连续,不保证每页的量相同)
select top 页面大小 * from users where id not in
    (select top (页数-1)*页面大小 id from users)
​
--3、offset fetch next only
select * from users order by id
    offset (页数-1)*页面大小+1 fetch next 页面大小 rows only;

 

19、分页实现

需要5个属性:

  ①数据总数

  ②页面大小(每页显示的数据条数)

  ③总页数

  ④当前页(页码)

  ⑤当前页的对象集合(实体类集合):每页所显示的所有数据

 

20、文件上传

需要引入2个jar包,commons-fileupload.jar和commons-io.jar。

(1)前端JSP页面

1 <form action="UploadServlet" method="post" enctype="multipart/form-data">
2     学号:<input name="sno" /><br/>
3     姓名:<input name="sname" /><br/>
4     上传照片:<input type="file" name="spicture"/><br/>
5     <input type="submit" value="注册" />
6 </form>
7 //enctype="multipart/form-data"是必需的,否则后台无法解析文件

 

(2)Servlet

 1 request.setCharacterEncoding("utf-8");
 2 response.setCharacterEncoding("utf-8");
 3 response.setContentType("text/html;charset=UTF-8");
 4 //上传
 5 try{
 6     boolean isMultipart = ServletFileUpload.isMultipartContent(request);
 7     if(isMultipart){//判断前台的from是否有mutipart属性
 8         FileItemFactory factory = new DiskFileItemFactory();
 9         ServletFileUpload upload = new ServletFileUpload(factory);
10 //通过parseRequest解析form中的所有请求字段,并保存到items集合中
11         List<FileItem> items = upload.parseRequest(request);
12         //遍历items中的数据
13         Iterator<FileItem> iter = items.iterator();
14                 while(iter.hasNext()){
15                     FileItem item = iter.next();
16                     String itemName = item.getFieldName();
17                     int sno = -1;
18                     String sname = null;
19                     //判断前台字段是普通form表单字段(sno、sname),还是文件字段
20                     if(item.isFormField()){
21                         if(itemName.equals("sno")){
22                             sno = Integer.parseInt(item.getString("UTF-8"));
23                         }else if(itemName.equals("sname")){
24                             sname = item.getString("UTF-8");
25                         }
26                     }else{
27                         //文件上传
28                         //getFieldName()获取普通表单字段name值
29                         //getName()获取文件名
30                         String fileName = item.getName();
31                         //获取服务器路径
32                         String path=request.getSession().getServletContext().getRealPath("upload");
33                         File file = new File(path,fileName);
34                         item.write(file);
35                         System.out.println(fileName + "上传成功!");
36                         return;
37                     }
38                 }
39             }
40 } catch (FileUploadException e) {
41     e.printStackTrace();
42 } catch (Exception e) {
43     e.printStackTrace();
44 }

 

(3)注意的问题

上传的目录upload:

  ①如果修改代码,则在tomcat重新启动时会被删除

    原因:当修改代码后,tomcat会重新编译一份class并且重新部署(重新创建各种目录)

  ②如果不修改代码,则不会删除

    原因:没有修改代码,class仍然是之前的class

 

(4)限制大小和类型

 1 //限制大小
 2 //限制大小需要在解析request之前就进行
 3 //设置上传时用到的临时文件的大小DiskFileItemFactory
 4 factory.setSizeThreshold(10240);//设置临时缓冲文件大小为10KB
 5 factory.setRepository(new File("d:\\uploadtemp"));//设置临时目录,存放临时文件
 6 //控制上传单个文件的大小20KB
 7 upload.setSizeMax(20480);
 8  9 //限制类型
10 //限制文件类型
11 String ext = fileName.substring(fileName.indexOf("."));
12 if(!(ext.equals("png") || ext.equals("gif") || ext.equals("jpg"))){
13     System.out.println("文件格式不正确。");
14     return;//终止
15 }

 

21、下载

下载不需要任何jar包。

下载的执行过程: ①请求(地址 a form),请求Servlet

         ②Servlet通过文件的地址,将文件转为输入流,读到Servlet中

         ③通过输出流将刚才已经转为输入流的文件输出给用户

 

(1)Servlet

 1 request.setCharacterEncoding("utf-8");
 2 String fileNmae = request.getParameter("fileName");
 3 //下载文件需要设置消息头
 4 response.addHeader("content-Type","application/octet-stream");
 5 response.addHeader("content-Disposition","attachement;filename=" + fileNmae);
 6 //Servlet通过文件的地址将文件转为输入流读到Servlet中
 7 InputStream in = getServletContext().getResourceAsStream("/rs/" + fileNmae);
 8 //通过输出流将刚才已经转为输入流的文件输出给用户
 9 ServletOutputStream out = response.getOutputStream();
10 byte[] bs = new byte[10];
11 int len = -1;
12 while((len=in.read(bs))!=-1){
13     out.write(bs,0,len);
14 }
15 out.close();
16 in.close();

 

(2)各文件的content-Type

文件类型Content-Type
二进制文件(任何类型的文件) application/octet-stream
Word application/msword
Excel application/vnd.ms-excel
PPT application/vnd.ms-powerpoint
图片 image/gif,image/bmp,image/jpeg
文本文件 text/plain
html网页 text/html

 

(3)各浏览器下载乱码问题

  ①Microsoft Edge

response.addHeader("content-Disposition","attachment;filename=" + URLEncoder.encode(fileNmae,"UTF-8"));

  ②Firefox

response.addHeader("content-Disposition","attachment;filename==?UTF-8?B?" + new String(Base64.encodeBase64(fileNmae.getBytes("UTF_8"))) + "?=");

 

22、EL

EL(Expression Language) 是为了使JSP写起来更加简单。可以替代JSP页面中的Java代码。

(1)EL示例

1、点操作符
${requestScope.user.name}
${域对象.域对象中的属性.属性.属性.级联属性}
2、中括号操作符([""]、[''])
${requestScope.user["name"]}

 

(2)点操作符和中括号操作符区别

  基本上上功能相同。点操作符使用方便。

  中括号操作符功能强大,可以包含特殊字符(. 、 -)。也可以使用变量,例如[name],name是一个变量。可以访问数组,例如${requestScope.hobbies[0]}、${requestScope.hobbies[1]}。

 

(3)获取map属性

1 //Servlet
2 Map<String,String> map = new HashMap<String,String>();
3 map.put("cn","中国");
4 requests.setAttribute("map",map);
5 
6 //JSP页面
7 ${requestScope.map.cn}
8 ${requestScope.map["cn"]}

 

(4)EL关系运算符和逻辑运算符

 

(5)Empty运算符

  判断一个值是否为null或不存在,是则返回为true。

1 ${empty requestScope["id"]}   //id值存在,为false
2 ${empty requestScope["pwd"]}  //pwd不存在或为null,为true

 

(6)EL的隐式对象(不需要new就能使用,自带的对象)

  ①作用域访问对象(EL域对象)

    pageScope、requestScope、sessionScope、applicationScope

    如果不指定域对象,则默认会根据从小到大的顺序依次取值

      例如:${sessionKey}

  ②参数访问对象:获取表单的数据、超链接中传的值、地址栏中的值

    ${param} → request.getParamter()

    ${paramValues} → request.getParamterValues()

      例如:${param.uname} 、${paramValues.hobbies[0]}

  ③JSP隐式对象:pageContext(可以获取JSP其他常见隐式对象)

      例如:获取request对象${pageContext.request}

 

23、JSTL

  JSTL(Java server pages standarded tag library,即JSP标准标签库)是由JCP(Java community Proces)所制定的标准规范。开发人员可以利用这些标签取代JSP页面上的Java代码,从而提高程序的可读性,降低程序的维护难度。

  需要引入2个jar包,jstl.jar和standard.jar。在JSP页面使用前还需要引入taglib。

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

 

(1)核心标签库

  ①通用标签库

  ②条件标签库

  ③迭代标签库

(2)通用标签库

  ①< c:set >

//1、在某个域之中(4个范围对象),给某个变量赋值
<%
    request.setAttribute("name","zhangsan");
%>
<c:set var="name" value="zhangsan" scope="request" />
//2、在某个域之中(4个范围对象),给某个对象的属性赋值
//给普通对象赋值
servlet中:request.setAttribute("user",user);
<c:set target="${requestScope.user}" property="name" value="zs"/>//给map对象赋值
servlet中:request.setAttribute("countries",map);
<c:set target="${requestScope.countries}" property="cn" value="中国"/>//注意:<c:set>可以给不存在的变量赋值,但不能给不存在的对象赋值

 

  ②< c:out >

//显示
${requestScope.name}
<c:out value="${requestScope.name}"/>
//name不存在,显示zs
<c:out value="${requestScope.name}" default="zs"/>
//将value中的值原样显示,否则显示a标签
<c:out value='<a href="https://www.baidu.com">百度</a>' escapeXml="true"/>  

 

  ③< c:remove >

//移除
<c:remove var="a" scope="request"/>

 

(3)条件标签库

  ①选择

//1、单重选择,输出结果为true
<c:if test="${10>2}" var="result" scope="request">
    ${requestScope.result}
</c:if>//2、多重选择,输出结果为权限为学生
<c:set var="role" value="学生" scope="request"/>
<c:choose>
    <c:when test="${requestScope.role == '老师'}">
        权限为老师
    </c:when>
    <c:when test="${requestScope.role == '学生'}">
        权限为学生
    </c:when>
    <c:otherwise>无权限</c:otherwise>
</c:choose>

 

(4)迭代标签库

  ①循环

//1、for循环,输出结果为0;1;2;3;4;5;
<c:forEach begin="0" end="5" step="1" varStatus="status">
    ${status.index};
</c:forEach>//2、foreach循环
<c:forEach var="name" items="${requestScope.names}">
    ${name}
</c:forEach>
//names是数组,相当于for(String name: names)

 

24、过滤器

Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息。

(1)编写Filter类

  创建一个类并实现Filter接口,doFilter()方法完成实际的过滤操作。

 1 public class MyFilter implements Filter {
 2  3     @Override
 4     public void init(FilterConfig filterConfig) throws ServletException {}
 5  6     @Override
 7     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
 8         System.out.println("拦截请求...");
 9         filterChain.doFilter(servletRequest,servletResponse);//放行
10         System.out.println("拦截响应...");
11     }
12 13     @Override
14     public void destroy() {}
15 }

 

(2)配置Filter

<filter>
    <filter-name>MyServlet</filter-name>
    <filter-class>com.my.filters.MyFilter</filter-class>
</filter><filter-mapping>
    <filter-name>MyServlet</filter-name>
    <url-pattern>/filters/MyServlet</url-pattern>
</filter-mapping>
​
//url-pattern放服务端Servlet,当访问MyServlet时会启动过滤器
//<url-pattern>设置为/*表示拦截所有请求
/*可以在一个<filter-mapping>元素中加入任意数目的<dispatcher>
  REQUEST---拦截HTTP请求,get和post
  FORWARD---只拦截通过请求转发方式的请求
  INCLUDE---只拦截通过request.getRequestDispatcher("").include()、通过<jsp:include page="..." />此种方式发出的请求
  ERROR---只拦截<error-page>发出的请求
*/

 

(3)过滤器链

  对于一个请求可以有多个过滤器进行拦截,拦截的顺序是过滤器在web.xml中的<filter-mapping>的声明顺序决定,先声明的先拦截。

 

25、监听器

(1)监听对象

  ①request

  ②session

  ③application

 

(2)监听对象的创建和销毁

  每个监听器各自提供2个方法:监听创建和监听销毁的方法。

    ①request—ServletRequestListener

    ②session—HttpSessionListener

    ③application—ServletContextListener

 

(3)监听对象的属性变更

  每个监听器提供3个方法:attributeAdded()、attributeRemoved()、attributeReplaced()

    ①request—ServletRequestAttributeListener

    ②session—HttpSessionAttributeListener

    ③application—ServletContextAttributeListener

 

(4)创建监听器

  创建一个类并实现相应的接口。

 

(5)配置

<listener>
    <listener-class>com.my.listeners.ContextSessionRequestListener</listener-class>
</listener>

 

26、Ajax

Ajax= Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。Ajax实现异步更新(与服务器交换数据并只更新需要更新的那部分网页)。

(1)Js实现Ajax

//1、创建一个XMLHttpRequest对象
xhr = new XMLHttpRequest();
//2、设置回调函数
xhr.onreadystatechange = callBack;
//3、调用open方法
//open(“get|post”,服务器地址,true)与服务器建立连接
//get方式传递值:xhr.open("get","MobileServlet?mobile="  + mobile,true);
xhr.open("post","MobileServlet",true);
//4、设置post头信息
//get:不需要设置此方法;post:需要设置此方法
//请求元素中不包含文件时上传:
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//请求元素中包含文件时上传:
xhr.setRequestHeader("Content-type","multipart/form-data");
//5、发送请求及相关信息
//get:send(null);post:send(参数值)
xhr.send("mobile=" + mobile);

 

XMLHttpRequest对象的属性:

  ①readyState:请求状态,只有4代表请求完毕

  ②status:响应状态,只有200代表响应正常

  ③onreadystatechange:设置回调函数

  ④responseText:响应格式为String

  ⑤responseXML:响应格式为XML

 

(2)Jquery实现Ajax

  ①方式一

function register1(){
    var $mobile = $("#mobile").val();
    $.ajax({
        url:"MobileServlet",       //服务器地址
        type:"post",               //请求方式
        data:"mobile=" + $mobile,  //数据
        success:function(result,testStatus){//成功时调用
            if(result == "true"){
                alert("此号码已存在!");
            }else{
                alert("此号码不存在!");
            }
        },
        error:function(xhr,errorMessage,e){//失败时调用
            alert("系统异常!");
        }
    })
}

  ②方式二

$.get(
服务器地址,
请求数据,
function(result){
    
},
返回值类型(“xml”,“json”,“text”)
)
$.post(
服务器地址,
请求数据,
function(result){
    
},
返回值类型(“xml”,“json”,“text”)
)
function register2(){
    var $mobile = $("#mobile").val();
    $.get(
        "MobileServlet",
        "mobile="+$mobile,
        function(result){
            if(result == "true"){
                alert("此号码已存在!");
            }else{
                alert("此号码不存在!");
            }
        },
        "text")
}

 

(3)Jquery方式的Ajax-load

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

$(xxx).load(
服务端地址,
请求数据,
function(result){  //该方法可有可无
    
}
)
function register3(){
    var $mobile = $("#mobile").val();
    $("#tip").load(
        "MobileServlet",
        "mobile="+$mobile
    )
}

Ajax介绍以及工作原理和实现详解

 

(4)Jquery方式的Ajax-getJSON

  通过该方法,请求数据类型是JSON,返回类型也是JSON。

$.getJSON(
服务器地址,
JSON格式的请求数据,
function(result){   //result类型是JSON格式
    
}
)
function register4(){
    var $mobile = $("#mobile").val();
    $.getJSON(
        "MobileServlet",
        {"mobile":$mobile},
        function(result){
            if(result.msg == "true"){
                alert("此号码已存在!");
            }else{
                alert("此号码不存在!");
            }
        }
    )
}

 

(5)Ajax处理JSON对象

  在JSP中要使用JSON对象,需要导入下面的jar包:

//1、Servlet
PrintWriter out = response.getWriter();
User user = new User("user","123");
JSONObject json = new JSONObject();
json.put("user",user);
out.print(json);
out.close();
​
//2、JSP
function testJSON(){
    $.getJSON(
        "JSONServlet",
        {"name":"user2"},
        function(result){
            //js需要通过eval()函数,将返回值转为一个js能够识别的json对象
            //JSON对象中只有一个
            var jsonUser = eval(result.user);
            alert(jsonUser.name + "---" + jsonUser.pwd);
            }
    )
}
​
function testJSON2(){
    $.getJSON(
        "JSONServlet",
        {"name":"user2"},
        function(result){
            //JSON对象中有多个
            var jsonUsers = eval(result);
            $.each(jsonUsers,function(i,element){
                alert(this.name + "---" + this.pwd);
            });
        }
    )
}

 

27、JNDI

  JNDI(Java Naming and Directory Interface,Java命名和目录接口)是SUN公司提供的一种标准的Java命名系统接口。将某一个资源(对象),以配置文件(tomcat/conf/context.xml)的形式写入。

//在context.xml文件中配置
<Environment name="jndiName" value="jndiValue" type="java.lang.String" />
​
//JSP中使用
Context ctx = new InitialContext();
String str = (String) ctx.lookup("java:comp/env/jndiName");
out.print(str);

 

28、连接池

  连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。常见的连接池:Tomcat-dbcp、dbcp、c3p0、druid。可以用数据源(javax.sql.DataSource)管理连接池。

  传统连接数据库的方式是应用程序直接创建一个指向数据库的连接。而引入连接池后,应用程序需要先获取数据源,再通过数据源在连接池中拿到连接。

(1)Tomcat-dbcp

  ①配置context.xml

<Resource
    <!-- 指定Resource的JNDI名字 -->
    name="users"
    <!-- 指定Resource的管理者:Container(由容器来创建Resource) 和Application(由Web应用来创建和管理Resource)-->
    auth="Container"
    <!-- 指定Resource的类型 -->
    type="javax.sql.DataSource"
    <!-- 处于活动状态的数据库连接的最大数量;为0表示不受限制 -->
    maxActive="400"
    <!-- 处于空闲状态的数据库连接的最大数量;为0表示不受限制 -->
    maxIdle="20"
    <!-- 连接处于空闲状态的最大等待时间(单位是毫秒;为-1表示无限制等待) -->
    maxWait="5000"
    <!-- 用户名和密码 -->
    username="root" password="12345678"
    <!-- 指定连接数据库的驱动程序的类名 -->
    driverClassName="com.mysql.jdbc.Driver"
    <!-- 指定连接数据库的URL -->
    url="jdbc:mysql://localhost:3306/jsppro" />
</Context>

 

  ②配置web.xml

<resource-ref>
    <res-ref-name>users</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

 

  ③使用数据源,更改连接对象Connection的获取方式

public static void getConnection() throws ClassNotFoundException, SQLException {
    Class.forName("com.mysql.jdbc.Driver");
    //将访问数据库的连接指向数据源
    try{
        Context ctx = new InitialContext();
        DataSource ds = (DataSource)ctx.lookup("java:comp/env/users");
        connection = ds.getConnection();
    }catch (NamingException e){
        e.printStackTrace();
    }
}

 

(2)dbcp

  引入commons-dbcp-1.4.jar包和commons-pool2-2.9.0.jar包。

  ①BasicDataSource方式(硬编码)

 1 //获取dbcp方式的ds对象
 2 public static DataSource getDataSourceWithDBCP(){
 3     BasicDataSource dbcp = new BasicDataSource();
 4     dbcp.setDriverClassName("com.mysql.jdbc.Driver");//设置连接数据库的驱动名
 5     dbcp.setUrl("jdbc:mysql://localhost:3306/jsppro");//设置连接数据库的URL
 6     dbcp.setUsername("root");//设置数据库的用户名
 7     dbcp.setPassword("12345678");//设置数据库的密码
 8     dbcp.setInitialSize(20);//设置初始化时,连接池中的连接数量
 9     dbcp.setMaxActive(10);//设置连接池中,处于活动状态的数据库连接的最大数量
10     dbcp.setMaxIdle(10);//设置连接池中,处于空闲状态的数据库连接的最大数量
11     return dbcp;
12 }

 

  ②BasicDataSourceFactory方式(配置文件)

    i.创建dbcpconfig.properties文件,添加以下内容

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jsppro
username=root
password=12345678
initialSize=20

 

    ii.获取DataSource

1 public static DataSource getDataSourceWithDBCPByProperties() throws Exception{
2     DataSource dbcp = null;
3     Properties props = new Properties();
4     InputStream input = new DBCPDemo().getClass().getClassLoader().getResourceAsStream("dbcpconfig.properties");
5     props.load(input);
6     dbcp = BasicDataSourceFactory.createDataSource(props);
7     return dbcp;
8 }

 

(3)c3p0

  提供了硬编码和配置文件两种方式,通过ComboPooledDataSource的构造方法参数区分:如果无参,硬编码;有参,配置方式。

  ①引入c3p0-0.9.5.2.jar和mchange-commons-java-0.2.15.jar,c3p0-oracle-thin-extras-0.9.1.2.jar(oracle需要)

  ②硬编码方式获取DataSource

 1 public static DataSource getDataSourceWithC3P0(){
 2     ComboPooledDataSource c3p0 = new ComboPooledDataSource();
 3     try {
 4         c3p0.setDriverClass("com.mysql.jdbc.Driver");
 5     } catch (PropertyVetoException e) {
 6         e.printStackTrace();
 7     }
 8     c3p0.setJdbcUrl("jdbc:mysql://localhost:3306/jsppro");
 9     c3p0.setUser("root");
10     c3p0.setPassword("12345678");
11     return c3p0;
12 }

 

  ③配置文件方式获取DataSource

    i.创建c3p0-config.xml,添加以下内容

<?xml version="1.0" encoding="UTF-8" ?>
<c3p0-config>
    <!--默认的配置-->
    <default-config>
        <!--如果要研究某个xml中可以设置哪些属性,找相关类的属性或setXxx()-->
        <property name="initialPoolSize">10</property>
        <property name="maxIdleTime">30</property>
        <property name="maxPoolSize">100</property>
        <property name="minPoolSize">10</property>
        <property name="maxStatements">200</property>
    </default-config>
    <!--这里没有默认配置中的属性,因此使用默认配置中的那些没有的属性-->
    <named-config name="users">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jsppro</property>
        <property name="user">root</property>
        <property name="password">12345678</property>
    </named-config>
</c3p0-config>

 

    ii.获取DataSource

1 public static DataSource getDataSourceWithC3P0ByXML(){
2     ComboPooledDataSource c3p0 = new ComboPooledDataSource("users");
3     return c3p0;
4 }

 

29、ApacheDbutils

Commons DbUtils 是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能勾简化JDBC应用程序的开发。

(1)下载commons-dbutils-1.7.jar

Apache Commons DbUtils下载地址

 

(2)重点类

  ①DbUtils:做一些辅助操作,如打开或关闭连接

  ②QueryRunner:增删改查,update()和query()

  ③ResultHandler:接口。有很多实现类,一个实现类对应于一种不同的查询结果类型

 

(3)ResultHandler实现类

  ①testArrayHandler:返回结果集中的第一行数据,并用Object[]接收

  ②ArrayListHandler:返回结果集中的多行数据,List<Object[]>接收

  ③BeanHandler:返回结果集中的第一行数据,用对象接收

  ④BeanListHandler:返回结果集中的多行数据,用对象接收

  ⑤BeanMapHandler:用Map<Integer,Student>接收

  ⑥MapHandler:返回结果集中的第一行数据,并用Map<String,Object>接收

  ⑦MapListHandler:返回结果集中的多行数据,并用List<Map<String,Object>>接收,{{id=2,name=ww},{id=3,name=zl}}

  ⑧KeyedHandler:返回结果集中的多行数据,并用Map<String,Map<String,Object>>接收,{ww={id=2, name=ww}, zl={id=3, name=zl}}

  ⑨ColumnListHandler:把结果集中的某一列保存到List中,[ww, zl]

  ⑩ScalarHandler:返回一个单值结果

 

(4)查询

1 public static void testArrayHandler() throws SQLException {
2     QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSourceWithC3P0ByXML());
3     String sql = "select * from student where id > ?";
4     Object[] student = runner.query(sql,new ArrayHandler(),1);//ArrayHandler在结果中只取一行
5     System.out.println(student[0] + "," + student[1] + "," + student[2]);
6 }

 

(5)增加

1 public static void add() throws SQLException {
2     QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSourceWithC3P0ByXML());
3     String sql = "insert into student(id,name,age) values(?,?,?)";
4     int count = runner.update(sql,new Object[]{4,"ls",20});
5     System.out.println(count);
6 }

 

(6)更新

1 public static void update() throws SQLException {
2     QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSourceWithC3P0ByXML());
3     String sql = "update student set name=?,age=? where id=?";
4     int count = runner.update(sql,new Object[]{"xl",22,4});
5     System.out.println(count);
6 }

 

(7)删除

1 public static void delete() throws SQLException {
2     QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSourceWithC3P0ByXML());
3     String sql = "delete from student where id=?";
4     int count = runner.update(sql,4);
5     System.out.println(count);
6 }

 

30、ThreadLocal

ThreadLocal叫做线程本地变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。可以为每个线程创建一个副本,每个线程可以访问自己内部的副本。

(1)数据库操作与ThreadLocal

  ①通过ThreadLocal,既保证数据的安全性,也保证了性能

  ②对于数据库来说,一个连接对应于一个事务,一个事务可以包含多个DML操作。Dao中包含了原子型的增删改查。一般来说,一个业务(Service)中的多个dao操作应该包含在一个事务中。因此借助ThreadLocal本身特性,可以在第一个dao操作时创建一个真正的connection对象,然后在其他几次dao操作时,会自动将该connection复制多个(connection只创建一个,因此该connection中的所有操作必然对应于同一个事务;ThreadLocal将connection在使用层面复制了多个,因此可以完成多个dao操作)。

 

(2)重点方法

  ①set():给ThreadLocal中存放一个变量

  ②get():从ThreadLocal中获取变量(副本)

  ③remove():删除副本

 

(3)事务流程

  ①开启事务(将自动提交改为手动提交)

  ②进行各种DML操作

  ③正常,将DML操作提交(全部成功);失败,将DML操作全部回滚(全部失败)

src/com/my/transaction · sumAll/JSP学习 - 码云 - 开源中国 (gitee.com)

 

31、元数据

元数据是描述数据的数据,主要是描述数据属性(property)的信息。例如一张表student(id,name),元数据就是id和name。

(1)类型

  ①数据库元数据:DatabaseMetaData

  ②参数元数据:ParameterMetaData

  ③结果集元数据:ResultSetMetaData

src/com/my/metaData · sumAll/JSP学习 - 码云 - 开源中国 (gitee.com)

 

32、自定义标签

(1)涉及到的类

 

(2)实现步骤

  ①编写标签处理类

    传统方式(JSP1.1):实现javax.servlet.jsp.tagext.Tag接口

    简单方式(JSP2.0):实现javax.servlet.jsp.tagext.SimpleTag接口

  ②编写标签描述符(tld文件)

  ③导入并使用

    导入:myTag.tld导入WEB INF或子目录下

    使用:引入具体要使用的tld文件<% @taglib uri="..." prefix="..." %>

  i.空标签(没有标签体的标签)

    < d:foreach >< /d:foreach > 、< d:foreach/ >

  ii.带标签体

    < d:foreach > xxx < /d:foreach >

  iii.带属性

    < d:foreach 属性名=“属性值” > xxx < /d:foreach >

 

(3)Tag接口

  没有循环时使用Tag接口。

  ①doStartTag():标签处理类的核心方法(标签体的执行逻辑)

    该方法有以下2个返回值:0/1

      int SKIP BODY = 0—标签体不会被执行

      int EVALBODY_ INCLUDE = 1—标签体会被执行

  ②doEndTag():标签执行完毕之后的方法.例如可以让标签在执行完毕后,再执行一次

      int SKIP PAGE =5—后面的JSP页面内容不被执行 int EVAL_PAGE = 6—后面的JSP页面内容继续执行

  Tag接口中的所有方法执行顺序:

    当JSP容器(Tomcat、jetty)在将.jsp翻译成.servlet(.java)的时候﹐如果遇到JSP中有标签,就会依次执行setPageContext() → setParent() → doStartTag() → doEndTag() → release()。

 

(4)javax.servlet.jsp.tagext.IterationTag接口

  IterationTag是Tag的子接口。如果有循环,就使用IterationTag。

  ①doAfterBody ():当标签体执行完毕之后的操作,通过返回值决定:

    int EVAL_BODY_AGAIN =2—重复执行 int SKIP_ BODY=0—不再执行

 

(5)javax.servlet.jsp.tagext.BodyTag接口

  BoyTag接口可以在标签体被显示之前,进行一些其他的“额外”操作。

    int EVAL_BODY_BUFFERED = 2,是doStartTag()的第三个返回值。代表一个缓冲区(BodyContent)。

  如果返回值是EVAL_BODY_BUFFERED,则服务器会自动将标签体需要显示的内容放入缓冲区中(BodyContent)。因此,如果要更改最终显示结果,只需要从缓冲区获取原来的数据进行修改即可。

 

(6)javax.servlet.jsp.tagext.SimpleTag接口

  将传统方式的doStartTag()、doEndTag()、doafterBody()等方法简化成了一个通用的doTag()方法。

  简单方式没有缓冲区,若需要修改显示内容,可以通过流实现。

  javax.servlet.jsp.tagext.JspFragment类:代表一块JSP元素(该块不包含scrlptlet,因此简单方式的tld文件中<body-content>不能是JSP)

  JspFragmen中有一个invoke(Writer varl)方法,入参是“流”,即如果要修改显示内容,只需要修改此流

  invoke(Writer var1):每调用一次invoke()方法,会执行一次标签体。

  SimpleTagSupport的 getJspBody()可以获取JspFragment对象。

  获取JSP内置对象:getJSPContext() → JSPContext → 转成子类PageContext → PageContext就是所有JSP内置对象的入口,即可以获取一切JSP内置对象。

 

(7)执行的流程

 

33、集群

(1)集群的好处

  ①负载均衡—分摊到多个操作单元上进行执行

  ②失败迁移—当一个服务器出现错误时,客户端可以去访问另一个服务器来完成操作

 

(2)服务端集群

  ①水平集群—将服务器安装在各个不同的计算机上(失败迁移)

  ②垂直集群—将多个服务器安装在同一个计算机上(负载均衡)

 

(3)服务器特点

  ①apache:特点是处理静态资源(html、js、图片)

  ②tomcat:特点是可以处理动态资源

 

(4)搭建集群

  ①下载apache服务器工具

Apache 下载地址

  ②apache配置

    修改conf/http.conf

    配置成windows服务,在命令行窗口执行以下命令

“D:\cluster\Apache24\bin\httpd.exe” -k install -n apache24

 

  ③准备tomcat

    i.将tomcat复制两份,并修改端口号(server.xml)。端口规划如下:

服务器server端口号http协议端口号ajp协议端口号
tomcat-a 1005 1080 1009
tomcat-b 2005 2080 2009

    ii.配置引擎Engine(server.xml)

tomcat-a:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-a">
tomcat-b:
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat-b">

 

    iii.打开集群开关(server.xml)

      打开以下注释。

<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>

 

  ④下载mod_jk.so文件,用来结合apache和tomcat

    下载 tomcat-connectors-1.2.40-windows-x86_64-httpd-2.4.x.zip 。

下载地址

  ⑤配置mod_jk.so

    i.存放位置:Apache24\modules

    ii.创建Apache24\conf\workers.properties

worker.list=controller,tomcata,tomcatb
​
#tomcata
worker.tomcata.port=1009
worker.tomcata.host=localhost
worker.tomcata.type=ajp13
#负载均衡的权重
worker.tomcata.lbfactor=1
​
#tomcatb
worker.tomcatb.port=2009
worker.tomcatb.host=localhost
worker.tomcatb.type=ajp13
worker.tomcatb.lbfactor=2
​
#controller
worker.controller.type=lb
worker.controller.balanced_workers=tomcata,tomcatb
#true表示session策略为sticky,false表示为session广播
worker.controller.sticky_session=false

 

    iii.配置Apache24\conf\mod_jk.conf(用于加载mod_jk.so和workers.properties)

#加载mod_jk.so
LoadModule jk_module modules/mod_jk.so
#加载workers.properties
JkWorkersFile conf/workers.properties
#表示拦截一切
JkMount /* controller

 

    iiii.httpd.conf在apache启动时自动加载,因此需要将mod_jk.conf引入到该文件,在文件末尾追加一下语句

include conf/mod_jk.conf

 

(5)注意

  ①要把系统变量CATALINA_HOME删除,因为如果配置了该变量,在点击startup.bat来启动tomcat时,会自动启动该变量指向的tomcat,导致本地计算机只能启动一台tomcat。

 

(6)分布式session策略

  ①sticky:将每一个用户的请求分给特定的服务器,后期的请求不会分给其他服务器,只分给第一次给的服务器

  ②session广播:自动同步session

    弊端:如果服务器太多,可能造成广播风暴(一个服务器的session,需要同步到其他所有的服务器)

  ③集中管理方式(推荐):将各个服务器的session集群存储到一个数据库中

posted @ 2021-08-09 22:46  sumAll  阅读(227)  评论(0编辑  收藏  举报