Servlet_如何使用Servlet?

Servlet

1.1、 Servlet概念

Servlet是服务器端的一个java小程序。它用于:处理,响应请求。

Servlet_如何使用Servlet?_第1张图片
Servlet概念

1.2、 Servlet的创建方式

在创建Servlet时一定要在web.xml中添加标签

为什么要在web.xml中设置url-pattern访问实现Servlet接口的类?

在项目src编写的实现类,tomcat将其编译成字节码文件放在WEB-INF中,外界不能直接访问,因此通过映射路径访问。
  • 方式一:实现Servlet接口

  • 方式二:继承GenericServlet

  • 方式三:继承HttpServlet【开发中使用】

1.3、 Servlet的生命周期

Servlet_如何使用Servlet?_第2张图片
创建ServletDemo类.PNG
Servlet_如何使用Servlet?_第3张图片
实现Servlet接口.PNG
Servlet_如何使用Servlet?_第4张图片
web.xml配置.PNG
结果.PNG
  • 实例化
  • 初始化init

      第一次请求时初始化一次。
    
  • 服务service

      每次请求都要调用一次service()方法
    
  • 销毁destroy

      服务器停止或者服务器移除该项目时销毁。
    

1.4、 Web.xml配置的背后细节

输入地址:http://localhost:8080/项目名称/映射路径

  • 中的两个中的值要一样才能寻找到

  • 中的映射路径要以 / 打头,不要落了。

  • 让Servlet实现类一开始就进行实例化和初始化

      如果想让Servlet的实现类在一开始就进行实例化和初始化,只需要在```标签中```
      添加```2```
    

背后细节:

      
      
        ServletDemo
        ServletDemo.ServletDemo
      
      
      
      
        ServletDemo
        /demo
      


    第一步:服务器通过映射路径url-pattern的demo对应的servlet-mapping的servlet-name
    第二步:根据得到的servlet-name在web.xml中寻找和它名字相同的servlet标签下的servlet-name
    第三步:根据对应的servlet-class中真实路径寻找到Servlet实现类的全路径从而访问
Servlet_如何使用Servlet?_第5张图片
Sevlet配置文件的访问细节

1.4.1、 Web.xml中映射路径的配置

  • 全路径匹配方式 : 以 / 开始

      例如:http://localhost:8080/项目名称/demo
      
      /demo   :   既是具体的全路径配置
    
  • 目录匹配方式 : 以 / 开始 ,以 * 结束

      流:http://localhost:8800/项目名称/aa/rqqhqih/whoqho
          http://localhost:8800/项目名称/aa/ss/wr/q/fg
    
      /aa/*   :   即只要在aa目录下的任意路径都可以
    
  • 扩展名匹配 : 以 * 开始 , 开头没有斜杠/

      例如:http://localhost:8080/项目名称/aa/bb/cc/*.do
    
      *.do    或者      *.(任意)  :   只要以对应扩展名结尾的都可以
    

1.5、 继承HttpServlet类创建一个Servlet

public class ServletDemo2 extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("*******doGet*******");
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("*******doPost*******");
    }
}

写完java的Servlet实现类后,完成web.xml配置。

  
    ServletDemo
    ServletDemo2.ServletDemo2
  
  
  
    ServletDemo
    /demo
  

结果:每访问一次输出一次doGet。(doGet和doPost服务器根据提交方式选择执行)

1.5.1、 HttpServlet子类调用doGet或doPost方法的背后细节

1:浏览器输入:    http://localhost:8080/项目名/demo

2: 在web.xml里面找到了ServletDemo这个类

3: 获得请求,调用ServletDemo这个类中的service方法。

4: 子类使用继承的父类HttpServlet中的Service(ServletRequest req,ServletResponse res)方法,
    

public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {

    HttpServletRequest request;
    HttpServletResponse response;
    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
}



5: 调用service(HttpServletRequest request, HttpServletResponse response)方法,根据提交方式调用对应的doXxx()方法

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();

        if (method.equals("GET")) {
            long lastModified = getLastModified(req);
            if (lastModified == -1L) {
                doGet(req, resp);
            }else if (method.equals("POST")){
                doPost(req, resp);
            } 
                ......


6: HttpServlet父类中有doGet()和doPost()方法,但是我们自己重写了doGet和doPost方法,
因此执行自己的doGet(),打印***doGet*****

2、 登陆案例

2.1 需求:写一个表单html登陆网页,提交账号和密码到服务器,服务器进行到数据库中进行校对,如果存在这样的用户数据,就登陆成功,反之就登录失败!

2.2 准备工作:

  • mysql驱动,C3P0的jar包,DBUtils的jar包,C3P0配置文件
  • 编写bean:User类,C3P0Utils工具类,数据库提供对应的User账号密码数据
  • 编写用户登录表单页面及处理请求Servlet登陆类
Servlet_如何使用Servlet?_第6张图片
包的分类.PNG

2.3 实现步骤:

1:导入相应的jar包,并添加至构建路径

要导入的jar包.PNG

2: 编写bean:User类,C3P0Utils工具类,并创建对应的数据库user

数据库user

数据库账号密码信息表.PNG

配置c3p0-config.xml配置文件

Servlet_如何使用Servlet?_第7张图片
c3p0-config.xml配置文件.PNG

编写C3P0Utils工具类

  • 提供获取连接池,获取连接及释放资源的方法
    public class C3P0Utils {
        // 提供获取连接池,获取连接和释放资源的方法
    
        // 根据c3p0-config.xml配置文件创建连接池
        private static DataSource ds = new ComboPooledDataSource();
    
        // 获取连接
        public static Connection getConnection() {
            Connection connection = null;
            try {
                connection = ds.getConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return connection;
        }
    
        // 释放资源
        public static void release(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection) {
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
    
            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        
        //获取连接池的方法
        public static DataSource getDataSource() {
            return ds;
        }
    }

编写bean:User类

  • 提供与数据库列名相同的变量,提供get/set方法

      public class User {
          private String username;
          private String userpsd;
      
          public User() {
              super();
              // TODO Auto-generated constructor stub
          }
      
          public String getUsername() {
              return username;
          }
      
          public void setUsername(String username) {
              this.username = username;
          }
      
          public String getUserpsd() {
              return userpsd;
          }
      
          public void setUserpsd(String userpsd) {
              this.userpsd = userpsd;
          }
      
          @Override
          public String toString() {
              return "User [username=" + username + ", userpsd=" + userpsd + "]";
          }
      }
    

编写用户登录页面及处理请求Servlet登陆类

  • 用户提交的数据发送至服务器的Servlet处理
  • 表单标签中action属性填写提交数据的地址,我们填写Servlet实现类的映射路径

用户表单页面Login.html

Servlet_如何使用Servlet?_第8张图片
表单登录页面.PNG

处理请求Servlet登陆类

  • 获取提交数据的账号和密码

  • 获取数据库中对应的信息,查询是否有符合条件的

      public class Login extends HttpServlet {
      
          // doGet()方法
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              // TODO Auto-generated method stub
              super.doGet(req, resp);
          }
      
          // doPost()
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              // 首先配置对应的xml文件,让提交的请求发送到该Servlet处理
      
              // 获取数据名为username的值
              String username = req.getParameter("username");
              // 获取数据名为userpsd的值
              String userpsd = req.getParameter("userpsd");
      
              // 使用DBUtils框架查询数据库中所有账号和密码与其输入的账号密码匹配的记录
              // 1:创建QueryRunner对象
              QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());
              // 2:编写sql语句
              String sql = "select * from User where username=? and userpsd=?";
              // 3:执行sql语句
              Object[] params = { username, userpsd }; // 占位符问号处的值
      
              try {
                  List users = runner.query(sql, new BeanListHandler<>(User.class), params);
      
                  if (users.size() > 0) {
                      resp.getWriter().println("Login Succed!");
                  } else {
                      resp.getWriter().println("Login Failed!");
                  }
              } catch (SQLException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
      }
    

配置HttpServlet子类Login类的web.xml文件

  
    Login
    Login.Login
  
  
  
    Login
    /login
  

将这里url-pattern的映射路径写到Login.html的表单标签的action属性中,提交的数据就能来到Login类处理

到这里,登陆案例就完成了,查看运行结果。

浏览器中输入地址:       http://localhost:8080/day14_ServletLoginDemo/login.html 。

在登陆的表单页面中填入账号密码

username : admin ,  userpsd : admin

数据库中没有这个用户的账号密码,登陆失败

username : lzl  ,   userpsd : lzl

数据库中有该用户的对应的信息,登陆成功  
Servlet_如何使用Servlet?_第9张图片
账密错误演示
账密错误结果
Servlet_如何使用Servlet?_第10张图片
账密正确演示
账密错误演示结果

3、ServletContext

3.1、 ServletContext概念

它是Servlet的上下文 , 每次项目加载到服务器时该项目都会实例化一个ServletContext对象,一个项目有且只有一个ServletContext对象。

3.2、 生命周期

    何时创建:

        1.服务器加载时,被服务器托管的项目都会实例化一个ServletContext对象
        2.项目发布时,实例化一个SoervletConetxt对象

3.3、 ServletContext的作用:

存/取数据

        getAttribute(String name) : 获取属性
        setAttribute(String name , Object obj) : 设置属性

        //1:存数据到关联的web.xml中
        context.setAttribute("name", "aobama");
        
        //2:获取存入到关联的web.xml中的属性
        String str = (String) context.getAttribute("name");

获取项目资源

方式一:
    获取到ServletContext对象,调用getResourceAsStream(String path)方法得到资源的流对象。
    将获取到的流对象用Properties加载出来。
    要注意的是getResourceAsStrem方法中的路径默认是在Tomcat/Webapps/项目名工程下的路径查找,而我们
    的资源被Tomcat默认放在项目工程下的的WEB-INF/classes中保存的,因此填入的路径就填相对路径就可以了

    //需求:获取该项目src下的my.properties文件

    //获取能够加载流文件的对象Properties
    Properties properties = new Properties();
    
    //获取当前项目的ServletContext对象
    ServletContext context = this.getServletContext();
    //获取my.properties文件的流对象
    InputStream inputStream = context.getResourceAsStream("WEB-INF/classes/my.properties");
    
    //将当前流对象用properties加载读取
    properties.load(inputStream);
    
    //获取my.properties文件中的值
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    //输出值
    System.out.println("username: "+username);
    System.out.println("password: "+password);



方式二:getRealPath(String path)

    自己创建输入流读取my.properties文件

    // 获取能够加载流对象的Properties对象
    Properties properties = new Properties();

    // 因为FileInputStream中要填入全路径 , 因此调用getRealPath()方法获取文件全路径
    String path = this.getServletContext().getRealPath("WEB-INF/classes/my.properties");

    // 获取文件流对象
    InputStream is = new FileInputStream(path);

    // 加载文件并获取文件中的内容
    properties.load(is);
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");

    System.out.println("username: " + username);
    System.out.println("password:  " + password);

            

方式三:类加载器读取my.properties文件

    //使用类加载器获取my.properties文件资源,这里的字节码对象可以是任意的class对象
    InputStream is = this.getClass().getClassLoader().getResourceAsStream("my.properties");

    //获取Properties对象,将该文件流对象加载
    Properties properties = new Properties();
    properties.load(is);
    
    //获取该资源中的内容
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    
    System.out.println("username: "+username);
    System.out.println("password: "+password);


浏览器输入:http://localhost:8080/项目名/映射路径
结果为:        username: jack
            password: 123
类加载器获取流对象的默认路径直接是在WEB-INF/classes下的,因此直接在后面拼接my.properties就可以正确加载。

获取全局参数

在web.xml中在中设置全局参数,与局部参数一样,
有两个值,设置它们的值,
在与其关联的Servlet中可以通过SevletContext对象的getInitParam(String)方法获得全局参数。

在web.xml中设置全局参数:
    可以把看做键值对

  
    姓名
    凌霄
  



ServletContextDemo中获取全局参数代码:    

//获得当前项目的ServletContext对象
ServletContext context = this.getServletContext();

//获取全局参数
System.out.println(context.getInitParameter("姓名"));

浏览器输入 : http://localhost:8080/ServletContextDemo3/demo
结果 : 凌霄

3.4、ServletContext案例一

需求:

在上面的登陆案例基础上,额外添加校对正确后,跳转到登录成功页面,显示内容:登陆成功,等待5秒后跳转。

跳转到新的页面,显示:欢迎某某,您是第n位登陆的用户!

思路:

  1. 在校对账密的Servlet中,如果登陆成功就跳转到登陆成功页面

  2. 编写登陆成功页面,实现5秒后跳转新页面的功能。(实现倒计时)

  3. 编写跳转后的页面。

     由于有计数,因此肯定要在某个地方定义一个计数器,将其定义在web.xml中,
     通过ServletContext对象可以方便的存入与取出该数据进行操作。
    

实现:

核对密码的Servlet代码:
    // 首先配置对应的xml文件,让提交的请求发送到该Servlet处理

    // 获取数据名为username的值
    String username = req.getParameter("username");
    // 获取数据名为userpsd的值
    String userpsd = req.getParameter("userpsd");

    // 获取校对后的用户
    List users = Service.check(username, userpsd, resp);

    if (users.size() > 0) {
        // 计数
        // 获取ServletContext对象,并取得属性为count的值
        ServletContext context = getServletContext();
        Object obj = context.getAttribute("count");// 获得了属性为count的值

        if (obj == null) { // 证明第一个登陆,设置计数器为1
            context.setAttribute("count", 1);
        } else { // 证明不是第一个登陆,取出count的值并+1存入
            context.setAttribute("count", (Integer) obj + 1);
        }

        resp.sendRedirect("Login_Succed.html");// html页面就在项目根目录下,跳转到该页面
    } else {
        resp.getWriter().write("Login Failed");
    }
}
登陆成功页面Login_Succed.html


Insert title here





    

登陆成功,5秒钟后跳转!

映射路径为login2的LoginSucced的Servlet类
public class LoginSucced extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 防止中文乱码,让客户端和服务端使用的码表一致
        response.setContentType("text/html;charset=UTF-8");

        // 获取ServletContext对象
        ServletContext context = getServletContext();
        // 获得当前属性值count的值
        int count = (Integer) context.getAttribute("count");

        response.getWriter().write("

欢迎光临,您是第" + count + "位登陆的用户!

"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }

****欢迎交流~~****

你可能感兴趣的:(Servlet_如何使用Servlet?)