MuLeI
做创造价值的人
MuLeI的小站

J2EE基础

J2EE基础
  • Java Web基础
    • Servlet的执行流程及生命周期
    • 请求与响应的结构
    • 请求转发与响应重定向
    • Session的原理
    • JSP九大内置对象
  • 数据处理
    • JDBC的使用步骤
    • Statement和PreparedStatement的区别

Java Web基础

一、Servlet的执行流程及生命周期

执行流程

https://www.mulei.ltd/wp-content/uploads/2021/07/servlet-flow.png
  • 服务器解析程序的web.xml文件,找到与请求匹配的urlservlet-name,根据servlet-name找到对应的servlet-class,然后对这个类进行实例化和初始化

  • tomcat应用服务器执行Servlet实例的service()方法(doGet/doPost),通过响应将数据返回给浏览器

  • Servlet默认情况下是在第一次访问时实例化,也可以通过web.xml配置load-on-startup,使其在服务启动的时候实例化

  • 对于Serlvet来说,在tomcat中有且仅有一个唯一的对象,tomcat不会创建Serlvet的多个实例

  • Servlet在并发环境下是如何处理的?
    Servlet是基于单例多线程处理并发情况,利用多线程技术提供web服务

  • 多线程处理的情况下,如何解决线程安全问题?
    所有的线程,都共享一个Servlet实例。在使用Servlet时,不允许在Servlet内创建存在状态的变量或对象,避免在并发访问时产生无法预期的结果

生命周期

  1. 装载:Java应用程序启动的时候,tomcat会扫描web.xml文件,得知当前应用有哪些Servlet,装载时并不会实例化Servlet(java层面的对象创建)
  2. 创建:当url第一次访问Servlet地址的时候进行创建,同时执行构造函数
  3. 初始化:Servlet在创建对象以后,会马上执行init()初始化函数,对Servlet进行初始化(Servlet自身专门用于初始化Servlet执行资源的方法)
  4. 提供服务:service()方法

    • servlce()方法:对于发来的请求(无论是post/get),一律使用servlet方法接收处理。如果将请求细化,service()方法下还可以细化为doGet()/doPost()方法
    • doGet():只处理get请求
    • doPost():只处理post请求
  5. 销毁:在web应用重启或关闭时使用destory()方法将Servlet的资源彻底销毁

二、请求与响应的结构

请求 request

https://www.mulei.ltd/wp-content/uploads/2021/07/http-request.png
  1. 请求行:说明了发送的方式(get/post),发送的地址,HTTP协议的版本号

  2. 请求头:说明了从浏览器到服务器发送到辅助信息

    • Accept-Language: zh-CN:说明浏览器优先使用中文
    • User-Agent:代表了用户的使用环境。帮助判断用户使用的是手机还会电脑进行的访问,然后根据浏览器的规格不同进行不同的展现
    • Content-Type:说明了提交的表单的格式(字符串或二进制流)
  3. 请求体:由浏览器向服务器发送的真实数据,请求体中,数据使用键值对的形式,“键”和“值”之间使用“=”连接,多个键值对之间使用“&”进行分隔。只有在post请求中才会存在,get请求中没有请求体这一项,请求体会被附加在url后面发送到服务器

响应 response

https://www.mulei.ltd/wp-content/uploads/2021/07/http-response.png
  1. 响应行:包含http版本、状态码、状态码的英文描述
    • HTTP状态码
    • 200:表示访问成功
    • 404:表示资源未找到
    • 500:代表的是服务器的内部错误。
  2. 响应头:表述了返回数据的一些辅助信息
    • Server:表示使用了哪种web服务器
    • Content-Type:表示数据返回给浏览器以后,浏览器采用什么样的方式进行处理呢。(text/html表示把返回的数据解释成html进行显示)
    • Date:响应数据产生的时间
  3. 响应体:服务器向浏览器返回的真实数据(html片段、二进制内容、xml)

三、请求转发与响应重定向

请求转发

https://www.mulei.ltd/wp-content/uploads/2021/07/http-requestDispatcher.png
  1. 请求转发是服务器跳转,只会产生一次请求(会将请求原封不动的转发给下一个请求)

  2. 请求转发语句:request.getRequestDispatcher().forward();

响应重定向

https://www.mulei.ltd/wp-content/uploads/2021/07/http-sendRedirect.png
  1. 响应重定向是浏览器端的跳转,会产生两次请求

  2. 响应重定向语句:response.sendRedirect();

四、Session的原理

https://www.mulei.ltd/wp-content/uploads/2021/07/http-session.png

Session又被称为用户会话,是指与客户端浏览器窗口绑定的,且存储在服务器内部的用户数据

Session的工作原理:客户端登录完成之后,服务器会创建对应的Session,Session创建完之后,会把 Session的id发送给客户端,客户端再存储到浏览器的Cookie中。只要当前浏览器没关闭,这个Cookie是一直存在的。这样客户端每次访问服务器时,都会带着SessionId,服务器拿到SessionId之后,在内存找到与之对应的 Session,这样就可以正常工作了

五、JSP(Java Server Pages)九大内置对象

https://www.mulei.ltd/wp-content/uploads/2021/07/JSP.png
  1. reqeust 获取用户参数,服务器通过request得到客户的数据
  2. response 服务器返回给客户端的数据
  3. session 用户会话
  4. application 可以存放全局的变量,可以实现用户之间的数据共享。生命周期同服务器生命周期一致
  5. out 用于在页面中输出
  6. page 当前的JSP页面
  7. pageContext 页面上下文对象,很少使用
  8. config web.xml中配置的全局参数或者Servlet参数,都可以使用config进行获取
  9. exception 异常对象,将其他JSP对象产生的异常在当前页面进行输出和控制(使用前,需要在配置指令中,将isError配置为’true”)

数据处理

六、JDBC的使用步骤

  1. 加载JDBC驱动
  2. 创建数据库连接Connection
  3. 创建命令Statement
  4. 处理结果ResultSet
  5. 关闭连接
// 标准JDBC操作五步骤
public class StandardJDBCSample {
    public static void main(String[] args) {
        Connection conn = null;
        try {
            // 1.加载并注册JDBC驱动
            // 如果使用JDBC操作数据库,需要先准备好其驱动包
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.创建数据库连接
            // url连接字符串格式:jdbc.mysql://[主机ip][:端口]/数据库名?参数列表。如果主机ip不写,默认为127.0.0.1,端口不写默认为3306,一般来说都要写
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename?useSSL=false&useUnicode=true&characterEncodeing=UTF-8&serverTimezone=Asia/Shanghai",
                    "root", "password");
            // 3.创建Statement对象
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("select * from tablename");
            // 4.遍历查询结果
            while (rs.next()) {
                Integer eno = rs.getInt(1); //通过字段位置获取
                String ename = rs.getString("ename");//通过字段名获取
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.关闭连接,释放资源
            try {
                if (conn != null && conn.isClosed() == false) {
                    conn.close();
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }
    }
}

七、Statement和PreparedStatement的区别

  • PreparedStatement是预编译的SQL语句,效率高于Statement,尤其执行复杂SQL语句或频繁执行某一SQL时,执行效率优势更明显
  • PreparedStatement支持参数化操作(?操作符),相比Statement使用字符串连接组织SQL语句更加灵活,可读性更好
  • PreparedStatement可以防止SQL注入,安全性高于Statement

  • Statement在运行时要经过两个步骤:
    i. Java会把SQL字符串进行解析,区分哪里是字段、条件、表名等
    ii. 根据解析的SQL语句,执行SQL
    这就意味着,如果我们执行了10万次,就要解析SQL语句10万次

  • PreparedStatement中,如果需要执行10万遍SQL,只需要解析一次SQL语句就可以了;而且会将解析的sql语句保存到数据库底层的内存中,当这条SQL再次执行时,只要把对应的数据传递到解析好的结果中就可以

  • SQL注入风险:SQL注入是专门针对Statement设计的,因为其是靠字符串拼接创建SQL语句的,所以对特殊字符没有做任何处理;而PrepareStatement则会将敏感字符处理掉,将其整体作为人名进行查询

例子

数据库中数据

https://www.mulei.ltd/wp-content/uploads/2021/07/1626877728.png

使用Statement

// 使用`Statement`
Class.forName(driverName);
Connection conn = DriverManager.getConnection(URL, username, password);
Statement statement = conn.createStatement();
String sql = "SELECT * FROM emp where ename = '" + ename + "' ";
System.out.println(sql);
ResultSet rs = statement.executeQuery(sql);

while (rs.next()) {
    System.out.println(rs.getString("ename") + "," +
    rs.getString("job") + "," +
    rs.getFloat("sal"));
}

// ename传入"SMITH"执行结果
SELECT * FROM emp where ename = 'SMITH'
SMITH,CLERK,800.0

// ename传入"SMITH' or 1=1 or '"执行结果
SELECT * FROM emp where ename = 'SMITH' or 1=1 or '' 
SMITH,CLERK,800.0
ALLEN,SALESMAN,1600.0
WARD,SALESMAN,1250.0
JONES,MANAGER,2975.0
MARTIN,SALESMAN,1250.0
BLAKE,MANAGER,2850.0
CLARK,MANAGER,2450.0
KING,PRESIDENT,5000.0
TURNER,SALESMAN,1500.0
ADAMS,CLERK,1100.0
JAMES,CLERK,1200.0
FORD,ANALYST,3000.0
MILLER,CLERK,1300.0

使用预编译PreparedStatement

// 使用预编译PreparedStatement
Class.forName(driverName);
Connection conn = DriverManager.getConnection(URL, username, password);
String sql = "SELECT * FROM emp where ename = ?";
System.out.println(sql);
PreparedStatement preparedStatement = conn.prepareStatement(sql);
preparedStatement.setString(1, ename);
ResultSet rs = preparedStatement.executeQuery();

while (rs.next()) {
    System.out.println(rs.getString("ename") + "," +
    rs.getString("job") + "," +
    rs.getFloat("sal"));
}

// ename传入"SMITH"执行结果
SELECT * FROM emp where ename = ?
SMITH,CLERK,800.0

// ename传入"SMITH' or 1=1 or '"执行结果
SELECT * FROM emp where ename = ?
本博客所有文章除特别声明外,均采用CC BY-SA 4.0 协议,转载请注明出处!

发表回复

textsms
account_circle
email

MuLeI的小站

J2EE基础
一、Servlet的执行流程及生命周期 二、请求与响应的结构 三、请求转发与响应重定向 四、Session的原理 五、JSP九大内置对象 六、JDBC的使用步骤 七、Statement和PreparedStatement的区别
扫描二维码继续阅读
2021-07-02