• 05-在Idea中编写Servlet程序


    前情回顾

    截至目前,我们已经总结了,如何配置Tomcat服务器(到官网下载资源,将bin目录配置到Path环境变量中,增加CATALINA_HOME环境变量),将Tomcat lib目录下的servlet-api.jar添加到CLASSPATH环境变量中,这样我们就可以使用JAVA EE的servlet接口。我们还学习了如何编写一个Servlet程序,它需要实现五个接口,知道了Tomcat是通过web.xml文件将路由和servlet程序关联。
    本节内容,是借助Idea来实现上述过程,并且进一步学习GenericServlet接口以及ServletConfig,ServletContext对象。

    利用Idea来创建项目并配置相关环境

    新建一个空项目

    这里选择Empty Project,键入javaTest作为项目名称
    在这里插入图片描述

    创建新模块

    这里不选择Jakarta EE, 而选择New Module
    在这里插入图片描述

    为模块引入框架支持

    在这里插入图片描述
    勾选Web Application选项,因为我们想要开发的是Web应用
    在这里插入图片描述
    现在可以看到目录结构按照Serlvet规范的目录给我们自动生成了,项目根路径就是web,但要注意的是这里不意味着我们的项目名称就是web,这里是虚拟的,后面在真正运行时可以配置项目名称。
    在这里插入图片描述

    配置Tomcat环境

    在这里插入图片描述
    在这里插入图片描述这一步是配置Tomcat本地开发环境,这里因为是我之前配置过,所以直接呈现这个界面,否则的话需要点击Configure文件找到Tomcat的根路径
    在这里插入图片描述
    这里就是部署,我们新建一个模块部署
    在这里插入图片描述
    这里的Application text就是项目根目录名称,你可以自己配置
    在这里插入图片描述

    添加模块的包依赖

    右击模块,点击Module Settings
    在这里插入图片描述
    添加jar包
    在这里插入图片描述
    这里加入的两个jar包,CTRL+ALT可以多选
    在这里插入图片描述
    成功以后你的External Libraries中除了jdk还可以看到你额外添加的包
    在这里插入图片描述

    编写Servlet程序

    在src目录下创建需要的类
    在这里插入图片描述
    由于我们下面需要连接数据库,所以需要数据库相关的jdbc实现,那么就需要在lib目录下导入相关的包。
    在这里插入图片描述
    StudentList.java

    package com.javaweb.servlet;
    import jakarta.servlet.*;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.sql.*;
    public class StudentList implements Servlet{
    
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    
        @Override
        public void service(ServletRequest servletRequest, ServletResponse servletResponse)
                throws ServletException, IOException {
                servletResponse.setContentType("text/html");
                PrintWriter writer = servletResponse.getWriter();
                Connection conn = null;
                PreparedStatement ps = null;
                ResultSet rs = null;
                try {
                    Class.forName("com.mysql.jdbc.Driver");
                    String url = "jdbc:mysql://localhost:3306/test_db?useSSL=false";
                    String user = "root";
                    String passwd = "1234";
                    conn = DriverManager.getConnection(url, user, passwd);
                    String sql = "select * from student";
                    ps = conn.prepareStatement(sql);
                    rs = ps.executeQuery();
                    while(rs.next()){
                        int id = rs.getInt("id");
                        String name = rs.getString("name");
                        int age = rs.getInt("age");
                        String s = "

    编号: " + id + " 姓名: " +name + " 年龄: " + age +"

    "
    ; writer.write(s); } }catch (Exception e){ e.printStackTrace(); }finally { if(rs != null){ try { rs.close(); }catch (Exception e){ e.printStackTrace(); } } if(ps != null){ try { ps.close(); }catch (Exception e){ e.printStackTrace(); } } if(conn != null){ try { conn.close(); }catch (Exception e){ e.printStackTrace(); } } } } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }

    index.html

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
      <title>wefwetitle>
    head>
    <body>
      <a href="/test/stu">student lista>
    body>
    html>
    
    
    <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_4_0.xsd"
             version="4.0">
        <servlet>
            <servlet-name>tttservlet-name>
            <servlet-class>com.javaweb.servlet.StudentListservlet-class>
        servlet>
        <servlet-mapping>
            <servlet-name>tttservlet-name>
            <url-pattern>/stuurl-pattern>
        servlet-mapping>
    web-app>
    

    下面是效果
    在这里插入图片描述
    点击超链接以后进行跳转
    在这里插入图片描述

    探究Servlet的接口方法

    GenericServlet

    每次我们想编写一个实现Servlet接口的程序,都需要实现5个方法,而很多时候其实只会使用service一个方法,这使得代码变得冗长与丑陋。为了解决这个方法,我们可以利用适配器设计模式,编写一个GenericServlet,它实现了除service方法以外的四个方法,并将service作为抽象方法,以后我们不需要直接实现Servlet接口,而是直接继承GenericServlet。

    package com.javaweb.servlet;
    import jakarta.servlet.*;
    
    import java.io.IOException;
    
    public abstract class GenericServlet implements Servlet{
    
        public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
                throws ServletException, IOException;
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {}
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
        
    
        @Override
        public String getServletInfo() {
            return null;
        }
        @Override
        public void destroy() {}
    }
    

    对Servlet对象的探究

    上面的GenericServlet有着其局限性,在改造它之前,我们先弄清楚几个问题。
    Servlet对象的生命周期是怎样的?即谁来创建它,什么时候创建,又什么时候销毁?
    作为客户端程序员而言,我们只是实现了service方法,从来没有自己去创建一个Servlet对象。事实上,Servlet对象是由Web服务器程序创建的,具体过程总结如下:

    1. 用户首次发送某个请求
    2. Tomcat创建对应的Servlet对象和ServletConfig对象(后续会探究ServletConfig对象)
    3. Servlet对象init方法被执行,ServletConfig对象作为参数传入
    4. service接口被调用
    5. 后续用户发送同一个请求,Servlet对象不再被创建,只是再次调用service方法
    6. 当服务器关闭时,destroy方法会被调用

    我们可以发现有个ServletConfig对象被传入到了init方法中,所以说如果我们不去重写GenericServlet的init方法,ServletConfig就会丢失,所以对GenericServlet做如下改造

    package com.javaweb.servlet;
    import jakarta.servlet.*;
    
    import java.io.IOException;
    
    public abstract class GenericServlet implements Servlet{
    
        private ServletConfig config ;
        public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
                throws ServletException, IOException;
        @Override
        public final void init(ServletConfig servletConfig) throws ServletException {
            config = servletConfig;
            this.init();
        }
        public void init(){}
    
        @Override
        public ServletConfig getServletConfig() {
            return config;
        }
    
    
        @Override
        public String getServletInfo() {
            return null;
        }
        @Override
        public void destroy() {}
    }
    

    创建一个私用变量config, 在init方法中将ServletConfig对象保存在里面,并且利用getServletConfig接口将该对象返回。事实上这个getServletConfig接口存在的意义就在于此。
    用户在继承GenericServlet时就不用重写init方法了,并且我们将其设置成final,用户也重写不了。那用户如果需要在init方法中执行一些初始化操作怎么办呢?可以看到提供了一个无参的init方法供用户重写,并且无参方法在有参方法中得到了执行。

    GenericServlet在jakarta EE中也提供了实现,所以以后不用直接实现Servlet接口。

    ServletConfig对象是什么东西?

    每个Servlet对象可能需要一些初始化信息,而初始化信息可以通过ServletConfig对象提供。
    它包含了如下四个方法

    String	getInitParameter​(String name);	
    Enumeration<String>	getInitParameterNames();	
    String	getServletName();
    ServletContext	getServletContext();	
    

    解释这几个接口,那么就先得进一步介绍web.xml的其它配置,web.xml的作用不仅仅是将Servlet服务和路径绑定,还可以配置一些初始化信息。

     <servlet>
            <servlet-name>tttservlet-name>
            <servlet-class>com.javaweb.servlet.StudentListservlet-class>
            <init-param>
                <param-name>nameparam-name>
                <param-value>tesparam-value>
            init-param>
            <init-param>
                <param-name>messageparam-name>
                <param-value>mesparam-value>
            init-param>
        servlet>
    

    通过init-param规定了初始化用的参数,一个name对应一个value

    public void service(ServletRequest servletRequest, ServletResponse servletResponse)
                throws ServletException, IOException {
            servletResponse.setContentType("text/html");
            PrintWriter writer = servletResponse.getWriter();
            Connection conn = null;
            PreparedStatement ps = null;
            ResultSet rs = null;
            ServletConfig config = getServletConfig();
            Enumeration<String> names = config.getInitParameterNames();
            while(names.hasMoreElements()){
                String name = names.nextElement();
                String val = config.getInitParameter(name);
                String init_param = "init_param: " + name + " init_value: " + val;
                writer.write(init_param);
                writer.write("
    "
    ); } }

    在这里插入图片描述
    上面列举了getInitParameterNames和getInitParameter的大概用法。

    ServletContext

    ServletContext context = getServletContext();
    context.getContextPath() //返回一个string,是项目的根路径名称
    context.getRealPath(文件名) //获取项目文件的在服务器上的绝对路径
    

    所有的servlet对象共享同一个ServletContext对象,它代表了全局配置信息,在web.xml中可以设置全局共享的初始化参数。

     <context-param>
            <param-name>sizeparam-name>
            <param-value>10param-value>
        context-param>
    
    Enumeration<String> params = context.getInitParameterNames();
            while(params.hasMoreElements()){
                String param = params.nextElement();
                writer.write("

    " + context.getInitParameter(param)+ "

    "
    ); }

    和ServletConfig对象一样有着上述的接口。

  • 相关阅读:
    使用队列集进行传递数据或信号同步
    新手小白学Java|零基础入门笔记|原来学Java可以这么简单
    常用的git分支管理方法都在这了
    shell之file命令
    Linux权限
    leetCode 214.最短回文串 + KMP
    一文读懂HTML的头部内容,希望有所帮助
    Java_StringBuilder类_StringBuffer类
    检测docker内存状态脚本
    docker 交叉编译镜像
  • 原文地址:https://blog.csdn.net/qq_43152622/article/details/127084432