环境配置

MySQL

常规操作

  • 配置:(在使用管理员打开cmd的前提下)
    • net start mysql:启动MySQL服务
    • net stop mysql:关闭MySQL服务
  • 登录:mysql -uroot -p>回车>输入密码(该方式可隐藏密码)
  • 远程登录:mysql -h主机IP地址 -uroot -p连接目标的密码
  • 退出:exit/quit

    目录结构

  • 安装目录:
    • bin:可执行二进制文件目录
    • data:用户数据目录
    • include:c#头文件目录
    • lib:运行所需要的库文件
    • share:mysql的一些错误信息
    • my.ini:mysql的配置文件
  • 数据目录:
    • 数据库——文件夹
    • 表——文件
    • 数据——具体数据

1

关于安装数据库时出现的一些问题:

在执行mysqld命令初始化数据库时,一开始出现了输入初始化命令后换行没有任何反应,就提示输入下一个命令,也试着去装了那个缺少的dll文件,不过好像不是缺这个的问题

最初的时候觉得是已经装过MySQL5的原因,就去把MySQL5卸载了,结果还是一样。

(这个时候在文档里复制命令的时候还一不小心复制成了安装MySQL8的命令,发现居然能运行的时候还惊喜了一下,结果后来发现不对劲的时候已经有点麻烦了)

后来想到是不是新的安装路径有中文的问题,就把整个MySQL8的文件夹全部移到了D盘根目录,试着重新安装了,但还是没用。

考虑到MySQL5卸载是不是没卸干净,在网上查了一下相关的问题,最后在以前装MySQL5做的笔记里找到了MySQL5的数据目录(默认在C:\ProgramData\MySQL\MySQL Server 5\data),把整个文件夹(C:\ProgramData\MySQL)删除之后初始化命令就能够成功执行了

2

等到继续安装的时候,执行命令后提示如下:

The service already exists!
The current server installed: (后面是原来包含中文的那个路径)

于是又去翻关于这个报错的帖子,想办法把之前这个中文路径的卸载掉,但是控制面板的程序面板是没有这个程序的(多半是因为莫名其妙的只装了一半,而且如果试图运行这个装了一半的MySQL也会报错),最后参照某个帖子的说法,删除了几个注册表,删完之后报错的第二行消失了。

最后在cmd执行了“sc delete MYSQL8”这一命令之后成功的卸掉了,之后也能够成功安装并运行正常的MySQL8.

Tomcat

目录结构

  • bin:可执行文件
  • conf:设置,配置文件
  • lib:运行库
  • webapps:默认主目录
    webapps目录下的root是根项目,不需要带文件夹名即可访问
    而root文件夹下的index.jsp或index.html为默认主页

IDEA

项目生成与配置

  1. 新建->项目->Java项目

    4

    如图,当项目名称与模块名称不同时,会自动将模块位置放在项目的下一级目录中,便于进行多模块项目开发

  2. 打开模块的右键菜单->添加框架支持->勾选Web应用程序->确定

    5

    选中web框架时,右侧会默认勾上创建web.xml,作为这个框架的配置文件

  3. 文件->项目结构->库->添加java项目库

    6

    为了后期能够使用一些常用的类,比如说servlet类,需要添加之前安装的Tomcat安装路径下,lib文件夹中的两个jar包(名称如图)

  4. 添加配置->点击加号->选择Tomcat服务器->本地

    7

  5. IDEA有时候自动识别Tomcat的安装路径,如果没有自动显示的话,需要去手动选择Tomcat的安装路径配置应用程序服务器8完成后,下方会有警告提示,此时需要点击部署选项卡,并添加一个工件9同时,应用程序上下文默认会在模块的名称后面加上-war-explored,在需要手动输入地址访问时很麻烦,可以只保留模块名。

    以上就成功创建了一个新的Web项目并且配置好了相应的库与Tomcat服务器。

  6. 除此之外,在文件->项目结构->工件中,可修改部署到服务器的方式10上面一种(图中的part1:war)为归档式,部署时会将文件压缩成一个包,上传后再解压,部署时间会比较长;

    下面一种(图中的part1:war exploded)为展开型,部署时直接将文件上传,部署时间相较更短一些,默认部署时也是选择这种。

目录结构

  • src:创建项目时默认的源文件夹,也可通过”文件->项目结构->模块”,添加新的源文件夹

  • web:存放各类jsp与html文件,部署到服务器后,该文件夹下的网页等可以被浏览器端访问

    但其中还包括一个名为web_inf的文件夹,该文件夹下是不允许浏览器端直接访问的

HTTP协议

即超文本传输协议,互联网上应用最为广泛的一种网络协议,用于定义客户端浏览器和服务器之间交换数据的过程。

作用

  1. 使浏览器和服务器之间更高效的传输数据
  2. 保证计算机正确快速的传输超文本文档
  3. 确定传输文档中的哪一部分
  4. 确定哪一部分内容先显示

    特点

    基于请求-响应模型,先有请求后有响应

    组成

    HTTP请求协议

1

(打开浏览器开发者工具【F12】可以监控到网页间请求信息如上)

  • 客户端连上服务器后,向服务器请求某个web资源,称之为客户端向服务器发送了一个HTTP请求
  • 包括请求行,请求头,请求体,请求头和请求体内容之间要用空行隔开
    • 请求行:
      依次包含请求类型,请求地址,HTTP协议版本
    • 请求头:
      用于描述客户端请求哪台主机,以及客户端的一些环境信息等,以键值对形式传递数据
    • 请求体:
      代表浏览器在POST请求中传递给服务器的参数,每个数据都是使用键值对形式,多个值用&连接,服务器接受到请求体后需要单独解析

HTTP请求方式

请求行中的POST值为请求方式,常见的请求方式有:POST、GET、DELETE、PUT

  • GET请求:
    • 向服务器特定资源发出查询请求,一般用于查询数据和资源
    • 请求查询的参数可以在浏览器地址栏显示
    • GET请求没有请求体
    • 请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接,也因此,传输数据会受到URL长度限制
      GET xxx.html?name=xxx&password=123456 HTTP/1.1
  • POST请求:
    • 向服务器提交数据,一般用在客户端将本地数据过资源提交给服务器,例如注册用户,将用户信息提交给服务器
    • POST请求会将请求的数据放置在HTTP请求体中,请求参数在地址栏中不显示
    • 多个参数同样用&连接,但参数不用和URL进行拼接

相较而言,因为保密性不高和传输长度受限,在完成数据提交操作时,一般用POST请求进行;而查询操作为了简便,则会使用GET请求进行

HTTP响应协议

  • 代表服务器给客户端回送的数据,包括一个响应行、若干响应头以及响应体,响应头和响应体内容之间用空行隔开
  • 包括响应行,响应头,响应体
    • 响应行:
      • 包含HTTP协议版本,用于描述服务器对请求的处理结果
      • 格式为:协议/版本 状态码 状态码描述
      • 状态码:服务器和浏览器用于确定状态的固定数字码
        • 200:请求成功
        • 302:请求重定向
        • 404:请求资源不存在,通常是访问路径写错或服务器删除了资源
        • 500:服务器内部错误
    • 响应头:
      用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理它所回送的数据
    • 响应体:
      服务器向客户端浏览器回送的正文,一般就是之前客户端所请求的资源

Servlet技术

Servlet是JavaWeb的核心程序,JavaWeb三大组件之一(Servlet,Filter,Listener),能够交互式的浏览和生成数据,实现动态web内容,获取网页的请求和响应都较为方便
在HTTP请求过程中,会把请求的参数存放在请求行的URL中,或者是请求体中,这个参数需要服务器来接收解析并处理,Servlet就是用来处理这个过程的

当无法快速创建Servlet时,可以在文件->项目结构->Facet->Web->源根

3

勾上工程路径下的src文件夹(如图中的E:\workspace\web1\src)

4

Requset获取请求内容

常用方法 实现功能 返回值
request.setAttribute(name,value) 设置name对应的属性值为value
request.getAttribute(name) 获取name对应的属性 Object,使用时可强制转换为之前设置的值所对应的类型
request.removeAttribute(name) 移除name对应的属性
request.getParameter(name) 获取name对应的表单项的值 String,即表单项提交上来的值
request.getParameterMap() 获取所有表单项的值 Map<String,String[]>,即所有表单项与其提交值组成的Map
request.setCharacterEncoding() 设置字符编码
request.getMethod() 获取请求方式 String,返回get,post等请求方式
request.getContextPath() 获取项目路径 String

Response获取响应内容

常用方法 实现功能
response.setContentType() 告知浏览器数据类型
response.setCharacterEncoding() 设置Response的编码方式
response.setHeader() 设置消息头
response.setStatus() 设置状态
response.addCookie() 添加Cookie
response.getOutputStream() 获取通向浏览器的字节流
response.getWriter() 获取通向浏览器的字符流

注:同一次请求处理中,字节流和字符流不能同时存在

页面跳转的实现

请求转发

请求转发是一种在服务器内部的资源跳转方式(不能跳到服务器之外的资源),有以下两个步骤:

  1. 通过request对象获取请求转发器对象:

    RequestDispatcher rd = request.getRequestDispatcher("要转发的页面路径");
  2. 使用RequestDispatcher对象来进行转发:

    rd.forward(request,response);

    但由于java可以连续调用,就省略了中间引入局部变量RequestDispatcher的过程,直接简写为:

requset.getRequestDispatcher("要转发的页面路径").forward(request,response);

在进行请求转发时,浏览器地址栏中的URL是不会改变的,所以,当要跳转的页面和现在的处理程序比较独立的时候,用请求重定向更合适——比如,checklogin完成了登录动作,要自动跳转到首页时,登录动作和首页是独立的两个内容,如果跳转到首页之后,地址栏还写着login.jsp就会很出戏

请求重定向

请求重定向类似于打电话时的呼叫转移,跳转操作是在浏览器,服务器之间发生,往往是两次请求:

  1. 客户端请求访问了某个程序,但由于某些原因,服务器需要客户端去访问一个新程序,此时会返回一个重定向的响应
  2. 客户端接收到重定向响应,按照这个重定向响应给的地址,去访问新程序,请求成功后又会返回一个响应

写作:

response.sendRedirect("跳转路径");

综上所述,请求重定向的特点如下:

  1. 请求重定向的过程是会改变浏览器地址栏中的URL的
  2. 因为第二次请求依旧是客户端发给服务器,而不是服务器内部的处理,所以仍旧不能访问WEB-INF下文件
  3. 由于有第二次请求,所以不能共享request,属性值的传递需要用session实现

具体使用技巧

在利用IDEA新建的servlet中,会默认生成这样一行注解:

@WebServlet(name = "newServlet", value = "/newServlet")

规定了这个Servlet的名称为”newServlet”,以及访问这个Servlet的路径是 “/newServlet”

而为了对用户的操作进行不同的处理,最常需要重写的方法就是servlet的doGet和doPost方法,两者分别对应了接受到Get请求和Post请求的情况下,servlet该完成的操作

在MVC架构中,常常会将servlet的访问路径,如 “/newServlet”,写成”/new.jsp”,使用户在输入URL访问new.jsp时,不会直接获取到这个网页,而是会先执行这个servlet重写的doGet方法,或者有时候还会完成一些数据处理,再转发至用户无法直接访问的web-inf文件夹下的view/new.jsp

而同样值得特别注意的是,servlet只是一个对数据进行处理的程序,在处理结束之后它并不会将数据的变动直接显示在网页上,所以在完成数据处理之后,一定要进行页面跳转,即使希望客户端仍旧留在当前页面,只是显示的数据改变,也必须要将请求和响应转发回来,否则客户端会一直停留在空页,等待响应

JDBC应用

JDBC就是Java的数据库连接,即用Java语言向数据库发送SQL语句

其原理就是,SUN提供一套访问数据库的规范(就是一组接口),称作JDBC,并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动

JDBC连接数据库

Mysql8以上版本,jdbc连接字符串与低版本不同,需要注意:

1.mysql8以上,项目引入jdbc的jar包后,项目会自动加载驱动类,如果需要手动加载类,需要注意类名与低版本不同

Class.forName("com.mysql.jdbc.Driver");  //低版本jdbc加载类
Class.forName("com.mysql.cj.jdbc.Driver"); //mysql8以上jdbc加载类

2.mysql8以上数据库,连接字符串需要加入useSSL和serverTimezone属性,否则报错,示例如下:

String url = "jdbc:mysql://localhost:3306/数据库名?characterEncoding=utf8& useSSL=false& serverTimezone=UTC"
Connection conn = DriverManager.getConnection(url);

由于需要连接数据库进行的操作很多,所以还可以将JDBC的连接操作封装成一个工具,例如:

public class JDBCUtils {
private static String url="";
private static String user="";
private static String password="";
private static String driver="";
static{
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("db.properties");
//这样可以将启动数据库所需的内容统一写入db文件中,如果要进行修改比较方便
Properties prop=new Properties();
try {
prop.load(is);
url=prop.getProperty("db.url");
user=prop.getProperty("db.user");
password=prop.getProperty("db.password");
driver=prop.getProperty("db.driver");
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}

public static Connection getConnection() {
/*需要执行数据库连接操作的时候就调用这个函数
异常也在函数内进行了处理,这样会让代码更加清晰明了
*/
Connection conn=null;
try {
conn=DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}

public static void close(Connection conn, Statement statement, ResultSet rs) {
//需要关闭数据库连接的时候就调用这个函数,也不用在servlet代码中反复写这些分支条件
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null)
{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

}
}

SQL语句执行

Connection conn = JDBCUtils.getConnection();
PreparedStatement pstm = conn.prepareStatement("select * from t_login where login_name=?");
pstm.setString(1,loginName);
ResultSet rs = pstm.executeQuery();

参照案例,可总结为以下步骤:

  • 连接数据库,用prepareStatement()方法创建一个SQL模板pstm
  • 写这个SQL模板时,可以用“?”作为参数,替代一些可能会变化的值,或者是需要外部传入的值
  • 得到PreparedStatement对象后,只要调用它的setXXX()方法为“?”赋值(xxx为数据类型)
  • 调用PreparedStatement对象的executeQuery()方法获取ResultSet对象

注意:

  1. PreparedStatement对象独有的executeQuery()方法是没有参数的,而Statement的executeQuery()是需要参数(SQL语句)的。因为在创建PreparedStatement对象时已经让它与一条SQL模板绑定在一起了,所以在调用它的executeQuery()和executeUpdate()方法时就不要参数了。
  2. 如果需要执行的SQL语句是会修改数据库内容的,比如UPDATE,DELETE,INSERT等,那么执行时所用的函数应该是execute()

PreparedStatement最大的好处就是在于重复使用同一模板,给予其不同的参数来重复的使用,这才是真正提高效率的原因。

Cookie与Session会话技术

Cookie是以小的文本文件形式(即纯文本),由服务端生成的,发送给客户端,某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据,设计用来在服务端和客户端进行信息传递

属性

名称和值

Cookie 的名称(Name) 和值(Value)是最重要的两个属性,创建Cookie时必须填写,其他属性可以使用默认值

名称或值如果包含非英文字母,则写入时需要使用encodeURIComponent()编码,读取时使用decodeURIComponent()解码

document.cookie = `${encodeURIComponent('用户名')}=${encodeURIComponent('张三')}`

一般名称使用英文字母,不要用中文,值可以用中文,但是要编码

失效(到期)时间

对于失效的Cookie,会被浏览器清除,而没有设置失效时间的cookie称为会话cookie,浏览器关闭该cookie就会消失

想让cookie长时间存在,需要设置Expires或Max-Age

//Expires
document.cookie = `username=alex; expires=${new Date('2100-1-01 00:00:00')}`

//Max-Age
//值为数字,表示当前时间+多少秒后过期,单位是秒
//表示5s后过期
document.cookie = `username=alex; max-age=5}`
document.cookie = `username=alex; max-age=${24*3000}}`
//0或负数,则会删除Cookie
document.cookie = `username=alex; max-age=0}`

Domain域

访问cookie的域名限制,只能访问在这个域名下cookie(不同域名)

Path路径

  • Path限定了Cookie访问范围(在同一域名,特定路径下)
  • 在目录下只能读写当前或上层路径的Cookie,不能读写下级路径的Cookie

HttpOnly

设置了HttpOnly属性的Cookie不能通过JS去访问

Secure安全标志

Secure限定了只有在使用了https而不是http的情况下才可以发送给服务器

注意:

  • 只有当Name、Domain、Path这3个字段都相同的时候,才是同一个Cookie
  • Domain\Path\Secure都要满足条件,还不能过期的Cookie才能随着请求发送到服务器端

工作原理

创建Cookie

当用户第一次浏览某个使用Cookie的网站时,该网站的服务器就进行了如下工作:

  1. 该用户生成一个唯一的识别码(Cookie id),创建一个Cookie对象
  2. 默认情况下它是一个会话级别的Cookie,存储在浏览器的内存中,用户退出浏览器之后被删除。如果网站希望浏览器将该Cookie存储在磁盘上,则需要设置最大时效(maxAge),并给出一个以秒为单位的时间(将最大时效设为0则是命令浏览器删除该Cookie);
  3. 将Cookie放入到HTTP响应报头,将Cookie插入到一个Set-Cookie HTTP请求报头中
  4. 发送该HTTP响应报头

设置存储Cookie

浏览器收到该响应报文之后,根据报文头里的Set-Cookied特殊的指示,生成响应的Cookie,保存在客户端。该Cookie里面记录着用户当前的信息

发送Cookie

当用户再次访问该网站时,浏览器首先检查所有存储的Cookies,如果某个存在该网站的Cookie(即该Cookie所声明的作用范围大于等于将要请求的资源),则把该Cookie附在请求资源的HTTP请求头上发送给服务器。

读取Cookie

服务器接收到用户的HTTP请求报文之后,从报文头获取到该用户的Cookie,从里面找到所需要的东西。

作用

根本作用就是在客户端存储用户访问网站的一些信息,典型的应用有:

  • 记住密码,下次自动登录
  • 购物车功能
  • 记录用户浏览数据,进行商品推荐

缺点

  • 每个特定域名下的Cookie数量有限,当超过单个域名限制之后,再设置cookie,浏览器就会清除以前设置的cookie

  • 存储量太小,只有4kb

  • Cookie会被附加在每个HTTP请求中,所以无形中增加了流量

  • 需要自己封装获取、设置、删除Cookie的方法

  • 由于HTTP请求中Cookie是明文传递的,所以安全性成问题(除非用HTTPS)

Session

  • Session代表服务器与浏览器的一次会话过程,这个过程是连续的,也可以时断时续的
  • 是一种 服务器端 的机制,Session对象用来存储特定用户会话所需的信息
  • 由服务端生成,保存在服务器的内存、缓存、硬盘或数据库中

工作原理

  1. 用户访问服务器
  2. 服务器启用Session
  3. 服务器为该用户创建一个SESSION
  4. 创建 之前检查用户发来的请求里是否包含一个SESSION ID
  5. 有,则说明之前该用户已经登录过并为此用户创建过SESSION,那么服务器就按这个ID把这个SESSION在服务器的内存中查找出来
    没有,则为该客户端创建一个SESSION并生成一个与此SESSION相关的SESSION ID。这个SESSION ID是唯一的、不重复的、不容易找到规律的字符串
  6. SESSION ID将被在本次响应中返回到客户端保存,而保存这个SESSION ID的正是COOKIE

作用

Session的根本作用就是在服务端存储用户和服务器会话的一些信息,典型的应用有:

  • 判断用户是否登录
  • 购物车功能

区别

cookie session
存放位置 客户端 服务端
存取方式 只能保管ASCII字符串,其他数据类型需要先进行编码 能够存取任何类型的数据,包括而不限于String\Integer\List\Map等。Session中也能直接保管Java Bean乃至任何Java类,对象等,运用起来十分便当
安全性 存储在客户端,对客户端是可见的,客户端的一些程序可能会窥探、复制以至修正Cookie中的内容;敏感信息如账号密码尽量不要写到Cookie中,最好进行Cookie信息加密,提交到服务器后再进行解密 存储在服务器上,对客户端是透明的,不存在敏感信息泄露的风险
有效期 只需要设置Cookie的过期时间属性为一个很大很大的数字,Cookie就可以在浏览器保存很长时间 由于Session依赖于名为JSESSIONID的Cookie,而Cookie JSESSIONID的过期时间默许为-1,只需关闭了浏览器(一次会话结束),该Session就会失效
对服务器造成的压力 保管在客户端,不占用服务器资源,假如并发阅读的用户十分多,Cookie是很好的选择。 保管在服务器端,每个用户都会产生一个Session,假如并发访问的用户十分多,会产生十分多的Session,耗费大量的内存
跨域支持上 支持跨域名访问 不支持跨域名访问

JSP深入

JSP的工作模式是请求/相应模式,客户端首先发出HTTP请求,jsp程序收到请求后会进行处理并返回处理结果,在一个jsp文件第一次被请求时,JSP引擎(容器)把该jsp文件转换成一个Servlet,而这个引擎本身也是一个Servlet

工作原理

  1. 客户端通过浏览器向服务器发出请求,在该请求中包含了请求的资源的路径,这样当服务器接收到该请求后就可以知道被请求的内容

  2. 服务器根据接收到的客户端的请求来加载相应的JSP文件

  3. Web服务器中的JSP引擎会将被加载的JSP文件转化为Servlet文件(.java)

  4. JSP引擎将生成的Servlet代码编译成Class文件

  5. 服务器执行这个Class文件

  6. 最后服务器将执行结果发送给浏览器进行显示

运行过程

  1. 客户端发送请求,请求访问jsp文件

  2. jsp容器先将jsp文件转化成一个java源文件(Java Servlet源程序),在转换过程中,如果发现jsp文件中存在任何语法错误,则中断转换过程,并向服务端和客户端返回出错信息

  3. 如果转换成功,则jsp容器将生成的java源文件编译成相应的字节码文件*.class。该class文件就是一个Servlet,Servlet容器会像处理其他Servlet一样来处理它

  4. 由Servlet容器加载转换后的Servlet类(.class文件)创建一个该Servlet(jsp页面的转换结果)实例,并执行Servlet的jspInit()方法jspInit()方法在Servlet的整个生命周期中只会执行一次

  5. 执行jspService()方法来处理客户端的请求,对于每个请求,jsp容器都会创建一个新的线程来处理它

    如果多个客户端同时请求该jsp文件,则jsp容器也会创建多个线程,使得每一个客户端请求都对应一个线程

    jsp运行过程中采用这种多线程的执行方式可以极大地降低对系统资源的需求,提高系统的并发量并缩短相应时间

    需要注意的是,由于第4步生成的Servlet是常驻内存的,所以响应的速度非常快

  6. 如果jsp文件被修改了,则服务器将根据设置来决定是否对该文件重新编译。如果需要重新编译,则使用重新编译后的结果取代内存中常驻的Servlet,并继续上述处理过程

  7. 虽然jsp效率很高,但在第一次调用的时候往往由于需要转换和编译,所以会产生一些轻微的延迟

    此外,由于系统资源不足等原因,jsp容器可能会以某种不确定的方式将Servlet从内存中移除,发生这种情况时,首先会调用jspDestroy()方法,然后Servlet实例会被加入“垃圾收集”处理

  8. 当请求处理完成后,响应对象由jsp容器接受,并将html格式的响应信息发送回客户端

注意:

  • 可以在jspInit()方法中进行一些初始化工作(建立数据库的连接、建立网络连接、从配置文件中获取一些参数等)

  • 可以在jspDestroy()方法中释放相应的资源等

  • 如果项目发布在Tomcat的webapps目录中,源文件和.class文件可以在“Tomcat安装目录/work/Catalina/localhost/应用名/”下找到

脚本和注释

表达式脚本(常用)

格式:<%=表达式%>

作用:在jsp 页面上输出数据

特点:

  • 所有的表达式脚本都会被翻译到 _jspService() 方法中
  • 表达式脚本都会被翻译成为out.print()输出到页面上
  • 由于表达式脚本翻译的内容都在 _jspService() 方法,所以 _jspService()方法中的对象都可以直接使用
  • 表达式脚本中的表达式不能以分号结束

代码脚本

格式: <% java 语句 %>
作用:可以在 jsp 页面中,编写我们自己需要的功能(写的是 java 语句)
特点:

  • 代码脚本翻译之后都在 _jspService 方法中
  • 代码脚本由于翻译到 _jspService()方法中,所以在 _jspService()方法中的现有对象都可以直接使用
  • 还可以由多个代码脚本块组合完成一个完整的 java 语句
  • 代码脚本还可以和表达式脚本一起组合使用,在 jsp 页面上输出数据

注释

  • html 注释:会被翻译到 java 源代码中,在_jspService 方法里,以 out.writer 输出到客户端
<!-- 这是 html 注释 -->
  • java 注释:会被翻译到 java 源代码中
<% 
// 单行 java 注释
/* 多行 java 注释 */
%>
  • jsp 注释:可以注掉jsp 页面中所有代码
<%-- 这是 jsp 注释 --%> 

九大内置对象

  1. request对象
    该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等),request对象的作用域为一次请求

  2. response对象
    代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端,response对象也具有作用域,它只在JSP页面内有效

  3. session对象

    是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以使复杂的对象类型,而不仅仅局限于字符串类型

  4. application对象

    可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”

  5. out对象

    用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流

  6. pageContext 对象

    是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。其创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象

  7. config 对象

    主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数

  8. page 对象

    代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针

  9. exception 对象

    处理jsp中出现的异常

JSTL标签库

JSTL 是 apache 对 EL 表达式的扩展(也就是说 JSTL 依赖 EL),虽然EL表达式方便了在JSP页面中的取值,但是遇到判断、循环的操作,只有EL表达式是远远不够的

故此,用来提升在 JSP 页面的逻辑代码的编码效率,使用标签来替换逻辑代码的直接书写

使用流程

导入jar包:jstl-1.2.jar

引入标签库:

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

常用标签

out标签

结合EL表达式将数据响应给浏览器,如果EL表达式没有取到数据则可以使用default属性声明默认值

set标签

将数据存储到指定的作用域中,默认是pageContext作用域

remove标签

删除作用域中的数据,默认是删除四个作用域中的符合要求的数据,可以通过scope属性指明要删除的作用域数据

<c:remove var="要删除数据的键名" scope="作用域名"/>

注意:

  1. 使用pageContext.removeAttriute(“键名”), 此方法会将四个作用域中的符合要求的数据全部删除

  2. 使用pageContext.removeAttriute(String name,int scope)

  3. 指明要删除的作用域中的数据 scope的值1为 pageContext,2为request ,3为 session,4为 application

  4. 使用request.removeAttibute(“键名”) 删除当前作用域符合要求的数据

  5. 使用session.removeAttibute(“键名”) 删除当前作用域符合要求的数据

  6. 使用application.removeAttibute(“键名”) 删除当前作用域符合要求的数据

单分支判断标签

可以根据EL表达式进行一定程度的单分支逻辑判断

<c:if test="${表达式}">数据</c:if>

注意:

  • test属性中书写的是EL表达式,或者说是EL表达式的逻辑表达式

  • 该标签只能进行EL表达式相关的逻辑判断。不能进行EL表达式不能获取的数据的逻辑处理

多分支判断标签

<c:choose>
<c:when test="${表达式}"></c:when>
<c:when test="${表达式}"></c:when>
..
<c:otherwise></c:otherwise>
</c:choose>

注意:符合条件后只会执行一个分支,其他分支不会执行

循环标签

<c:foreach>
循环体
</c:foreach>

属性:

  • begin:声明循环的开始位置

  • end:声明循环的结束位置

  • step:声明循环的步长

  • varStatus:声明变量记录循环状态 ,例如变量名:i

  • ${i.index} 获取当次循环的下标

  • ${i.count} 获取当次循环的次数

  • ${i.first} 判断是否是第一次循环

  • ${i.last} 判断是否是最后一次循环

  • items:声明要遍历的数据,可以是集合和数组等

  • var:声明变量记录每次遍历的结果。可以做循环体中使用使用EL表达式获取遍历出来的数据

注意:记录的数据存储到了作用域中可以直接使用El表达式进行获取

过滤器Filter

过滤器Filter技术,能够实现对所有Web资源的管理,如实现权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能

filter的配置

filter由filter和filter-mapping两组标签组成,如果Servlet版本大于3.0,也可以使用注解的方式来配置filter

web.xml可以配置的filter属性都可以通过@WebServlet的方式进行配置,但如果存在多个过滤器,使用web.xml配置filter可以控制过滤器的执行顺序

filter的接口方法

init()接口

与Servlet中的init()方法类似,filter中的init()方法用于初始化过滤器。开发者可以在init()方法中完成与构造方法类似的初始化功能。如果初始化代码中要用到FilterConfig对象,则这些初始化代码只能在filter的init()方法中编写,而不能在构造方法中编写。

public void init(FilterConfig fConfig) throws ServletException{
//此处内容为开发者定义的初始化代码...
}

doFilter()接口

doFilter方法类似于Servlet接口的service()方法。当客户端请求目标资源时,容器会筛选出符合标签中的filter,并按照声明的顺序依次调用这些filter的doFilter()方法。
doFilter()方法有多个参数,其中参数request和response为Web服务器或filter链中的上一个filter传递过来的请求和响应对象
参数chain代表当前filter链的对象,只有当前filter对象中的doFilter()方法内部需要调用FilterChain对象的doFilter方法时,才能把请求交付给filter链中的下一个filter或目标程序处理

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
//此处内容为开发者定义的初始化代码
...
//传递filter链
chain.doFilter(request, response);
}

destroy()接口

filter中的destroy()方法Servlet中的destroy()作用类似,在Web服务器卸载filter对象之前被调用,用于释放被filter对象打开的资源。

public void destroy(){
//此处内容为开发者进行终止操作的代码
}

filter的生命周期

当Web容器启动时,会根据web.xml中声明的filter顺序依次实例化这些filter。然后在Web应用程序加载时调用init()方法,随机客户端有请求时调用doFilter()方法,并且根据实际情况的不同,doFilter()方法可能被调用多次。最后Web应用程序卸载时调用destroy()方法。

监听器Listener

作用:监听某个事件的发生,状态的改变

实现监听:

创建类实现监听器接口

web.xml文件中配置(注册)监听器

<listener> <listener-class>url</listener-class></listener> 

Listener监听三个域对象创建与销毁

ServletContext域

监听ServletContext域对象的创建与销毁:实现ServletContextListener接口

ServletContext域对象的生命周期

  • 创建:启动服务器时创建

  • 销毁:关闭服务器或者从服务器移除项目

@WebListener
public class MyServletContextListener implements ServletContextListener{

@Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("初始化");
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
System.out.println("销毁了");
}

}

作用: 利用ServletContextListener监听器在创建ServletContext域对象时完成一些想要初始化的工作或者执行自定义任务调度

ServletRequest域

监听ServletRequest域对象的创建与销毁:实现ServletRequestListener接口

ServletRequest域对象的生命周期

创建:访问服务器任何资源都会发送请求(ServletRequest)出现,访问.html和.jsp和.servlet都会创建请求

销毁:服务器已经对该次请求做出了响应

@WebListener
public class MyServletRequestListener implements ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent arg0) {
System.out.println("ServletRequest销毁了");
}
@Override
public void requestInitialized(ServletRequestEvent arg0) {
System.out.println("ServletRequest创建了");
}

}

HttpSession域

监听HttpSession域对象的创建与销毁:实现HttpSessionListener接口

HttpSession域对象的生命周期

创建:只要调用了getSession()方法就会创建,一次会话只会创建一次

销毁:

  1. 超时(默认为30分钟)

  2. 非正常关闭,销毁

  3. 正常关闭服务器(序列化)

@WebListener
public class MyHttpSessionListener implements HttpSessionListener{

@Override
public void sessionCreated(HttpSessionEvent arg0) {
System.out.println("HttpSession创建了");
}

@Override
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("HTTPSession销毁了");
}

}

作用:每位用户登录网站时都会创建一个HTTPSession对象,利用这个统计在线人数

Listener监听三个域对象属性状态的改变

  • 监听HttpSession属性的改变:实现HttpSessionAttributeListener接口
  • 监听ServletContext属性的改变:实现ServletContextAttribute接口
  • 监听ServletRequest属性的改变:实现ServletRequestAttribute接口

Listener监听HttpSession域对象存值的状态变更,这两种监听器不用注册

监听对象与session绑定和解除绑定的动作,让JavaBean实现HttpSessionBindingListener接口:

public class MyHttpSessionBindingListener implements HttpSessionBindingListener {
@Override
public void valueBound(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
System.out.println("绑定了");
}

@Override
public void valueUnbound(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
System.out.println("解绑了");
}
}

用于监听现在session的值是钝化(序列化),还是活化(反序列化)的动作,JavaBean实现HttpSessionActivationListener接口和Serializable接口。

  • 钝化(序列化):把内存中的数据存储到硬盘中
  • 活化(反序列化):把硬盘中的数据读取到内存中
public class Bean implements HttpSessionActivationListener ,Serializable{
@Override
public void sessionDidActivate(HttpSessionEvent arg0) {
System.out.println("活化了");
}
@Override
public void sessionWillPassivate(HttpSessionEvent arg0) {
System.out.println("钝化了");
}
}

session的钝化活化的用意:

session中的值可能会很多,并且有很长一段时间不会去使用这个内存中的值,那么可以考虑把session中的值存储到硬盘上(钝化),等下一次要使用的时候,从硬盘上提取到内存中(活化)。

设置session在一定时间内钝化:

  • 在Tomcat里面 conf/context.xml中配置:

    配置后对所有运行在该服务器中的项目生效。

  • 在Tomcat里面conf/Catalina/localhost/context.xml中配置(没有就创建一个context.xml文件):

    对localhost生效,如localhost:8080/

  • 在自己的web工程项目中的META-INF/context.xml中配置:

    只对当前的工程项目生效。

配置内容:

  • maxIdleSwap:

    设置经过该时间就钝化。

  • directory:

    设置钝化后存放的目录,没有就自动创建。

<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="lrving"/>
</Manager>
</Context>