Servlet服务器(上篇)

今日内容

一、Servlet
二、HTTP
三、HttpServlet

零、 复习昨日

见晨考

一、Servlet

1.1 介绍

javaweb开发,就是需要服务器接收前端发送的请求,以及请求中的数据,经过处理(jdbc操作),然后向浏览器做出响应.


我们要想在服务器中写java代码来接收请求,做出响应,我们的java代码就得遵循tomcat开发规范


因此Tomcat提供了开发的规范,就是servlet.

Servlet就是运行在服务器上的程序,可交互式的接收服务器的请求,并可以做出响应


总结Servlet的作用:

  • 运行在服务器,是一个服务器端的程序
  • 接收客户端请求,向客户端做出响应
  • 动态网页(jsp)

1.2 第一个Servlet程序

1.2.1 创建web项目

Servlet服务器(上篇)_第1张图片

Servlet服务器(上篇)_第2张图片

手动补全目录结构

Servlet服务器(上篇)_第3张图片

1.2.2 pom依赖


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0modelVersion>

  <groupId>com.qfgroupId>
  <artifactId>day46_servletartifactId>
  <version>1.0-SNAPSHOTversion>
  
  
  <packaging>warpackaging>


  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    <maven.compiler.source>1.8maven.compiler.source>
    <maven.compiler.target>1.8maven.compiler.target>
  properties>

  <dependencies>
    
    <dependency>
      <groupId>javax.servletgroupId>
      <artifactId>javax.servlet-apiartifactId>
      <version>3.1.0version>
    dependency>
    
    <dependency>
      <groupId>javax.servlet.jspgroupId>
      <artifactId>javax.servlet.jsp-apiartifactId>
      <version>2.3.1version>
    dependency>
  dependencies>
project>

1.2.3 编写Servlet

  • 实现javax.servlet.Servlet接口
  • 重写方法
  • 在核心方法service()里面完成接收请求,做出响应
package com.qf.servlet;

import javax.servlet.*;
import java.io.IOException;


public class MyServlet1 implements Servlet {
    @Override
    public void init(ServletConfig config) throws ServletException {}

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 核心方法,服务,在这个方法中可以完成接收请求,做出响应
     * @param req 用来处理请求的对象
     * @param res 用来处理响应的对象
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // 通过请求对象,可以获得请求的ip
        String ip = req.getRemoteAddr( );
        System.out.println("ip = "+ip );

        // 响应
        // res.getWriter()获得字符输出流
        // .writer() 写出到浏览器字符(中文可能乱码)
        res.getWriter().write("i'm Response,Hello");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {}
}

1.2.4 配置Servlet

因为服务器中会有很多servlet,浏览器发请求如何确定访问哪一个servlet类?

此时就需要做一个映射: 请求路径和servlet类的映射,即发出的请求由哪个servlet类来处理


配置需要写在webapp/WEB-INF/web.xml中


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
    
    <servlet>
        
        <servlet-name>servlet1servlet-name>
        
        <servlet-class>com.qf.servlet.MyServlet1servlet-class>
    servlet>

    
    <servlet-mapping>
        
        <servlet-name>servlet1servlet-name>
        
        <url-pattern>/s1url-pattern>
    servlet-mapping>
web-app>

浏览器发出请求,经过web.xml中配置的信息,

  • 匹配url-pattern>/s1
  • 通过servlet-name找到servlet类
  • 再通过servlet-class,找到servlet类路径
  • 该servlet就可以执行service()

1.2.5 部署项目

web项目已经开发完毕,将项目部署到服务器Tomcat

配置Tomcat

Servlet服务器(上篇)_第4张图片

部署项目

Servlet服务器(上篇)_第5张图片

image-20221125104144365

Servlet服务器(上篇)_第6张图片

1.2.6 启动访问

启动项目

image-20221125143816377

访问发出请求

http://localhost:8080/day46/s1

Servlet服务器(上篇)_第7张图片

Servlet服务器(上篇)_第8张图片

Servlet服务器(上篇)_第9张图片

-Dfile.encoding=utf-8

1.3 执行流程分析【理解】

  package com.qf.util;
import com.alibaba.druid.pool.DruidDataSource;
 import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.File;
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.sql.*;
 import java.util.ArrayList;
import java.util.List;
 import java.util.Properties;
public class DBUtil {
    // 创建Properties类对象,专用于操作properties文件   
    private static final Properties properties = new Properties( );    // 声明Druid连接池的连接池对象  
    // 数据连接,一般称作数据源 
    dataSource    private static DruidDataSource dataSource;  
 static {    
 try {            
 InputStream inputStream = DBUtil.class.getResourceAsStream("/jdbc.properties");            properties.load(inputStream);            // 不需要由我们加载驱动            // 需要给dataSource赋值            
     dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);} catch (Exception e) {            System.out.println("加载驱动异常!!");            e.printStackTrace( );        }    }public static Connection getConnection() {       
     Connection conn = null;       
     try {            // 不需要我们获得连接           
         // 而是通过Druid获得          
         conn = dataSource.getConnection( );       
     } catch (Exception e) {          
         System.out.println("获得连接出异常!!!");            e.printStackTrace( );      
     }        
     return conn;    
 }   
      /**     * 关闭所有流     */  
                        public static void closeAll(Connection conn, Statement s) {     
                           
      if (conn != null) {          
          try {              
              conn.close( );           
          } catch (SQLException throwables) {                throwables.printStackTrace( );            
                                            
                                        }        
      }        
                            if (s != null) {
                                try {                
                                    s.close( );            
                                } catch (SQLException throwables) { 
                                    throwables.printStackTrace( );  
                                } 
                            }
                        }
                        public static void closeAll(Connectionconn, Statement s, ResultSet rs) { 
                                if (conn != null) {            
                                    try {                
                                        conn.close( );           
                                    } catch (SQLException 
                                             throwables) { 
                                        throwables.printStackTrace(
                                        );            
                                    }        
                                }        
                            if (s != null) {
                                try {
                                    s.close( );
                                } catch (SQLException throwables) {
                                    throwables.printStackTrace( ); 
                                }       
                            }
                              
                         if (rs != null) {
                             try {
                                 rs.close( );
                             } catch (SQLException throwables) {
                                 throwables.printStackTrace( ); 
                             }
                         }
                        }
                        /**     * 封装查询方法,返回一个对象     * 参数1 执行查询的SQL,预处理的,条件用?占位     * select * from tb_user where id = ? and username = ? and password = ?     * 参数2 结果要封装的类     * 参数3 给?赋值,不定长参数,是数组     * 1,admin,123456     */    
                        public static <T> T selectOne(String sql, Class<T> t, Object... args) {
                            Connection conn = getConnection( );        PreparedStatement ps = null; 
                            ResultSet rs = null; 
                            T target = null; 
                            try {    
                                ps = conn.prepareStatement(sql);            for (int i = 0; args != null && i < args.length; i++) {                ps.setObject(i + 1, args[i]);                                   }  
     rs = ps.executeQuery( );           
                                /**             * 创建对象             * 从数据库取出数据,并设置对象属性             */            
 while (rs.next( )) {  
         target = t.newInstance( ); 
        Field[] declaredFields =t.getDeclaredFields( );              for (int i = 0; i < declaredFields.length; i++) {                    Field field = declaredFields[i];
 Object value = rs.getObject(field.getName( ));              
                                                                                                                      // 破解私有  
                                                                                                                      field.setAccessible(true);                 
                                                                                                                  // 给对象的该字段赋值 
                                                                           field.set(target, value);
                                                                       }    
 }   
 } catch (Exception e) {            
 e.printStackTrace( );       
                            
 } finally {            closeAll(conn, ps, rs);        }        return target;    }public static <T> List<T> selectAll(String sql, Class<T> t, Object... args) {        Connection conn = getConnection( );        PreparedStatement ps = null;        ResultSet rs = null;        T target = null;        ArrayList<T> list = new ArrayList<>( );        try {            ps = conn.prepareStatement(sql);            for (int i = 0; args != null && i < args.length; i++) {                ps.setObject(i + 1, args[i]);            }​            rs = ps.executeQuery( );            /**             * 创建对象             * 从数据库取出数据,并设置对象属性             */            while (rs.next( )) {                target = t.newInstance( );                Field[] declaredFields = t.getDeclaredFields( );                for (int i = 0; i < declaredFields.length; i++) {                    Field field = declaredFields[i];                    Object value = rs.getObject(field.getName( ));                 // 破解私有  
  field.setAccessible(true);                    // 给对象的该字段赋值
  field.set(target, value);                }                list.add(target);            }        } catch (Exception e) {            e.printStackTrace( );        } finally {            closeAll(conn, ps, rs);        }        return list;    }/**     * 增删改方法一样     */    public static boolean update(String sql, Object... args) {        Connection conn = getConnection( );        PreparedStatement ps = null;        int num = 0;        try {            ps = conn.prepareStatement(sql);            for (int i = 0; args != null && i < args.length; i++) {                ps.setObject(i + 1, args[i]);            }            num = ps.executeUpdate( );        } catch (Exception e) {            e.printStackTrace( );        } finally {            closeAll(conn, ps);        }        return num > 0 ? true : false;    }}

如果启动失败,要及时查看控制台日志

  1. 立即加载解析web.xml文件

    1)服务器内就会知道当前服务器能接收哪些请求路径

    2)也知道请求路径被哪个servlet处理

    3)如果web.xml中有错,启动会失败,要及时查看控制台日志

    4)常见的错误就是url-partten写错了

  2. 启动成功,跳转至index.jsp页面(如果没有该页面,报错404)

  3. 浏览器发出请求

    1)发出请求路径,根据ip找到服务器,再根据8080找到服务器中的程序htttp://localhost:8080

    2)然后再通过名字找到服务器中的项目,默认访问首页(index.jsp),找不到报错404

    htttp://localhost:8080/day46

    3)然后发出具体的请求路径 http://localhost:8080/day46/a

  4. 发出的请求会经过web.xml中配置的路径去匹配

    1)web.xml中没有匹配到路径,报错404

    2)web.xml中有匹配的路径,就找对应的servlet让其执行

  5. servlet执行service()方法,完成接收请求,和做出响应的动作

    如果后台出问题,主要是指java代码报错,页面会报错500

1.4 使用细节

1.4.1 web.xml中url-partten写错

  
    <servlet-mapping>
        
        <servlet-name>servlet1servlet-name>
        
        
        <url-pattern>s1url-pattern>
    servlet-mapping>
Caused by: java.lang.IllegalArgumentException: Invalid <url-pattern> s1 in servlet mapping

1.4.2 首页问题

项目启动,默认访问webapp/index.jsp页面

没有该页面,启动报404

也可以通过web.xml文件来修改默认启动访问页面


<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

    
    
    <welcome-file-list>
        <welcome-file>login.htmlwelcome-file>
    welcome-file-list>
    
     
web-app>

1.4.3 访问路径问题

现在的访问路径是

http://localhost:8080/day46/

这个访问路径,是在配置Tomcat时给设置的

image-20221125153714293 image-20221125153746569

再访问就是http://localhost:8080/java2217

image-20221125153823894

1.4.4 修改端口

image-20221125154318886 image-20221125154344957

1.4.5 web.xml标签有顺序

有些web.xml上方的约束文件不同,即web.xml内容的顺序不同.如果有报错,鼠标悬浮查看错误信息,就会发现,标签有顺序要求!! 顺序如下

image-20230324111952985

1.5 映射细节

映射细节就是浏览器发出请求,访问servlet时的一些操作

1.5.1 映射路径模板

第一种: 固定路径

<servlet-mapping>
    <servlet-name>servlet1servlet-name>
    
    <url-pattern>/s1url-pattern>
servlet-mapping>

第二种: 模糊匹配路径

<servlet-mapping>
    <servlet-name>servlet1servlet-name>
    
    <url-pattern>/*url-pattern>
servlet-mapping>

第三种: 多层路径

<servlet-mapping>
    <servlet-name>servlet1servlet-name>
    
    
    <url-pattern>/a/*url-pattern>
servlet-mapping>

第四种: 后缀匹配

<servlet-mapping>
    <servlet-name>servlet1servlet-name>
    
    <url-pattern>*.dourl-pattern>
servlet-mapping>

1.5.2 多个请求到同一个Servlet

一个Servlet可以处理多个请求

多个映射路径映射可以到同一个Servlet,比如设置url-partten为/*,那么就可以任何请求都就可以找到MyServlet1执行


也可以这么设置,让/s1 /s11 /s111都可以访问到MyServlet1

servlet-mapping>     
<servlet-name>servlet1servlet-name>
<url-pattern>/s1url-pattern>
<url-pattern>/s11url-pattern>
<url-pattern>/s111url-pattern>  
servlet-mapping>

或者这么写

    <servlet-mapping>
        <servlet-name>servlet1servlet-name>
        <url-pattern>s1url-pattern>
    servlet-mapping>
    <servlet-mapping>
        <servlet-name>servlet1servlet-name>
        <url-pattern>s2url-pattern>
    servlet-mapping>

1.5.3 一个请求到多个Servlet

一个请求不能到多个Servlet!!! 不能这样配置!!!

1.6 Servlet生命周期【理解】

  • 创建
    • 请求到达该Servlet时才创建
    • 且只创建一次,单例对象
  • 初始化
    • 创建完对象,立即初始化
    • 也就初始化一次
  • 服务
    • 请求到达该类,对象创建完毕,初始化完毕后就执行service干活
    • 后续,每次请求到达该类,service()都会执行
  • 死亡
    • 服务器关闭时销毁

二、HTTP

浏览器和服务器之间是通过http协议在传输数据.


超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是一个基于请求与响应模式的、无状态的、应用层的协议,运行于TCP协议基础之上。


课下查询书籍<<网络通信>> <<计算机组成原理>>

2.1 在http请求中有请求报文

通过浏览器的开发者工具(F12)监听任何一个网站的请求响应过程,就可以看到请求报文和响应报文

Servlet服务器(上篇)_第10张图片

请求行内有请求方式(GET),和请求路径(/s?wd=java)

image-20221125172859447

ps: 后续就可以通过servlet获得这些数据

2.2 在http响应中有响应报文

Servlet服务器(上篇)_第11张图片

响应行中有协议(http/1.1) ,响应状态码(200) ,响应信息(OK)

Servlet服务器(上篇)_第12张图片

2.3 GET和POST

HTTP中常见的请求方式

  • get
  • post

GET请求

  • 数据会通过浏览器地址栏发送
  • 数据量大小有限制,最多4kb
  • 请求数据不安全
  • 效率相对较高

开发中建议,通过服务器查询数据使用get请求,比如findOne,findAll等信息

前端技术中,如何发送一个get请求?

  • form表单指定method=get
  • a标签
  • ajax
  • window.location.href = “/day46/index/html”
  • 地址栏手动输入

POST请求

  • 数据是隐藏的,在地址栏看不见,但是是在请求体中
  • 数据量大小不限
  • 数据相对安全
  • 效率相对较低

开发中建议,使用POST向服务器发送数据,登录,注册,更新,上传文件等

前端技术中,如何发送一个POST请求?

  • form表单的method=post
  • ajax

三、HttpServlet

之前Servlet程序,需要实现Servlet接口,有不好之处

  • 实现接口,重写所有方法,但是只关心如何接收请求和做出响应
  • service()方法可以处理各种各样的请求,不够专一

基于以上问题,服务器就提供一个专业用于处理HTTP请求和响应的一个Servlet类,HttpServlet,该类是抽象类,内部提供一些方法,供选择重写

Servlet服务器(上篇)_第13张图片

  • 浏览器发出get请求,那么就重写doGet方法处理get请求
  • 浏览器发出post请求,那么就重写doPost方法处理post请求
package com.qf.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


public class MyServlet3 extends HttpServlet {


    /**
     * 重写doGet,处理get请求
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        System.out.println("接收get请求" );

    }

    /**
     * 重写doPost,处理post请求
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("接收post请求" );
    }
}
    <servlet>
        <servlet-name>servlet3servlet-name>
        <servlet-class>com.qf.servlet.MyServlet3servlet-class>
    servlet>
    <servlet-mapping>
        <servlet-name>servlet3servlet-name>
        <url-pattern>/s3url-pattern>
    servlet-mapping>
    <form action="/day46/s3" method="post">
        <input type="submit" value="登录post">
    form>
    <hr>
    <form action="/day46/s3" method="get">
        <input type="submit" value="登录get">
    

作业/总结/掌握

1 整个创建配置部署启动servlet过程
2 理解执行流程
3 画出javaweb开发图
4 前端如何发送请求?
5 前端的请求方法有哪些?
6 后台有哪些处理不同请求方式的方法?
   doGet
   doPost
7 前端请求通过什么和后台服务器关联?
  web.xml配置映射路径

四、IDEA+Maven-jdk版本

修改idea中java版本

Servlet服务器(上篇)_第14张图片

Servlet服务器(上篇)_第15张图片

Servlet服务器(上篇)_第16张图片

Servlet服务器(上篇)_第17张图片

Maven-POM文件中设置编译版本

 <build>
    <plugins>
      
      <plugin>
        <groupId>org.apache.maven.pluginsgroupId>
        <artifactId>maven-compiler-pluginartifactId>
        <configuration>
          <source>1.8source>
          <target>1.8target>
        configuration>
      plugin>
    plugins>
  build>

你可能感兴趣的:(Servlet,JavaWeb,servlet,服务器,java)